Пользовательский обратный отсчет RxJava продолжает "тикать" после утилизации - PullRequest
1 голос
/ 14 июня 2019

Я сделал простой класс таймера, используя 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 timer), как я показываю во втором примере кода, я вижу, что старый таймер все еще активен и обновляет индикатор выполнения (и старый, и новый таймер обновляют индикатор выполнения,поэтому прогресс скачет между этими 2 значениями)

Я не понимаю этого, почему таймер не полностью утилизируется?Почему «старый таймер» продолжает обновлять значения?

РЕДАКТИРОВАТЬ:

Вот как класс таймера ведет себя во фрагменте:

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 () on) ...

Ответы [ 2 ]

2 голосов
/ 14 июня 2019

Я не уверен, почему вы делаете это таким образом, но есть оператор 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);
    }
}
0 голосов
/ 14 июня 2019

Попробуйте очистить экземпляр также через GC. добавьте следующее во все места, где вы звоните timer.cancel(). Установка его в нуль уведомит GC, что экземпляр таймера готов к очистке.

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