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