简体   繁体   English

RxJava自定义倒数计时器在处置后继续“滴答”

[英]RxJava custom countdowntimer continues to “tick” after disposed

I made a simple timer class using RxJava Observables: 我使用RxJava Observables创建了一个简单的计时器类:

public abstract class CountDownTimer {

    private final TimeUnit timeUnit;  
    private final Long startValue; 
    private Disposable disposable;

    public CountDownTimer(Long startValue, TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
        this.startValue = startValue;
    }

    public abstract void onTick(long tickValue);

    public abstract void onFinish();

    public void start(){
        Observable.zip(
                        Observable.range(0, startValue.intValue()), 
                        Observable.interval(1, timeUnit),  
                        (integer, aLong) -> startValue - integer)   
                .subscribeOn(Schedulers.computation())  
                .observeOn(AndroidSchedulers.mainThread())  
                .subscribe(new Observer<Long>() {   
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        onTick(aLong);
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                        onFinish();
                    }
                });
    }

    public void cancel(){
        if(disposable!=null) {
            disposable.dispose();
        }
    }
}

I use this class to set progress on a ProgressBar (initiation from a method in Fragment ): 我使用此类在ProgressBar上设置进度(从Fragment的方法初始化):

timer = new CountDownTimer(QUESTION_TIME, TimeUnit.SECONDS) {
        @Override
        public void onTick(long tickValue) {
            //set progress color
        }

        @Override
        public void onFinish() {
            //set progress color
        }
    };
    timer.start();

When onFinish() tick from timer, onDestroyView from fragment, and other places in my fragment code, I call this: 当onFinish()从计时器开始计时,onDestroyView从片段开始计时,以及片段代码中的其他位置时,我将其称为:

if(timer != null){
        timer.cancel();
    }

And I can see from logging that cancel() is called and it is disposed of. 从记录中可以看到cancel()被调用并被丢弃。 However, even when resetting timer (I have a class variable Countdowntimer timer) like I showns in my second code example, I can see that the old timer is still active and updates the progressbar (both the old, and new timer updates the progressbar, so progress jumps between these 2 values). 但是,即使像我在第二个代码示例中所示重置计时器(我有一个类变量Countdowntimer计时器)一样,我也可以看到旧计时器仍处于活动状态并更新进度条(旧计时器和新计时器都更新进度条,因此进度会在这两个值之间跳跃)。

I don't understand this, why is the timer not completly disposed of? 我不明白,为什么计时器没有完全处理掉? Why does the "old timer" still continue to update the values? 为什么“旧计时器”仍然继续更新值?

EDIT: 编辑:

This is how the timer class behaves in a fragment: 这是计时器类在片段中的行为:

TICK 25    //first call to create new timer
TICK 24
TICK 23
TICK 22
TICK 21
TIMER CANCELLED    //first call stopped. timer.cancel() called (which then calls disposable.dispose() in CountDownTimer.class)
TICK 25    //second call
TICK 25    // somehow the first call also start again? 
TICK 24
TICK 24
TICK 23
TICK 23
TICK 22
TICK 22
TIMER CANCELLED    //cancel second call
TICK 21    //first or second call still continues
TICK 20
TICK 19
TICK 18

And it will continue to "stack on" more timers (which I called dispose() on)... 而且它将继续“堆叠”更多的计时器(我称之为dispose())。

I'm not sure why you do this in this way, but there is an operator intervalRange that gets you this in fewer steps. 我不确定为什么要用这种方法,但是有一个运算符intervalRange可以使您以更少的步骤完成此操作。 Also managing the disposable could be a problem if you are reusing the same Countdowntimer . 如果您要重复使用相同的Countdowntimer则管理一次性物品可能会有问题。 Try this: 尝试这个:

class CountdownTimer {
    SerialDisposable disposable = new SerialDisposable();

    //...

    public void start() {
         disposable.set(
             Observable.intervalRange(0, startValue, 
                 1, timeUnit, AndroidSchedulers.mainThread())
             .subscribe(
                 tick -> onTick(startValue - tick)
                 error -> error.printStackTrace()
                 () -> onFinish()
             )
         );
    }

    public void cancel() {
         disposable.set(null);
    }
}

Try to clear the instance through GC too. 也尝试通过GC清除实例。 add the following to all the places where you are calling timer.cancel() . 将以下内容添加到要调用timer.cancel()所有位置。 Setting it to null will notify the GC that the timer instance is ready to be cleared. 将其设置为null将通知GC该计时器实例已准备好被清除。

if(timer != null) {
   timer.cancel();
   timer= null;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM