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

时间:2019-06-14 11:56:19

标签: java rx-java rx-java2

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

我使用此类在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()被调用并被丢弃。但是,即使像在第二个代码示例中所示重置计时器(我有一个类变量Countdowntimer计时器)一样,我也可以看到旧计时器仍处于活动状态并更新进度条(旧计时器和新计时器都更新进度条,因此进度会在这两个值之间跳跃)。

我不明白这一点,为什么计时器没有完全处理掉?为什么“旧计时器”仍然继续更新值?

编辑:

这是计时器类在片段中的行为:

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

它将继续“堆叠”更多的计时器(我称之为dispose())...

2 个答案:

答案 0 :(得分:2)

我不确定您为什么要这样做,但是有一个运算符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);
    }
}

答案 1 :(得分:0)

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

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