RxJava 自定义倒数计时器在处理后继续 "tick"

RxJava custom countdowntimer continues to "tick" after disposed

我使用 RxJava Observables 制作了一个简单的计时器 class:

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();
        }
    }
}

我使用此 class 来设置 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();

当计时器的 onFinish() 滴答、片段的 onDestroyView 以及我的片段代码中的其他地方时,我称之为:

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

而且我可以从日志记录中看到调用了 cancel() 并且它已被处理掉。但是,即使像我在第二个代码示例中显示的那样重置计时器(我有一个 class 变量 Countdowntimer 计时器),我也可以看到旧计时器仍然处于活动状态并更新进度条(旧计时器和新计时器更新进度条,因此进度会在这两个值之间跳跃)。

我不明白,为什么定时器没有完全处理掉?为什么 "old timer" 仍然继续更新值?

编辑:

这是计时器 class 在片段中的行为方式:

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

它会继续 "stack on" 更多计时器(我在上面调用了 dispose())...

也尝试通过GC清除实例。将以下内容添加到您呼叫的所有地方 timer.cancel()。将其设置为 null 将通知 GC 计时器实例已准备好被清除。

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

我不确定您为什么要这样做,但是有一个运算符 intervalRange 可以让您以更少的步骤完成此操作。如果您重复使用相同的 Countdowntimer,管理一次性用品也可能是一个问题。试试这个:

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);
    }
}