废话不多说直接上代码:
public class RxCountDown {
public static Observable<Integer> countdown(int time) {
if (time < 0) time = 0;
final int countTime = time;
return Observable.interval(0, 1, TimeUnit.SECONDS)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<Long, Integer>() {
@Override
public Integer call(Long increaseTime) {
return countTime - increaseTime.intValue();
}
})
.take(countTime + 1);
}
}
代码比较简单,利用interval()
定时发送Observable
,通过map()
将0、1、2、3...
的计数变为...3、2、1、0
倒计时。通过take()
取>=0
的Observable
。
使用时:
RxCountDown.countdown(5)
.doOnSubscribe(new Action0() {
@Override
public void call() {
appendLog("开始计时");
}
})
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
appendLog("计时完成");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
appendLog("当前计时:" + integer);
}
});
这样就实现了一个5秒的倒计时。
运行结果:
D/HIDETAG: <-- 当前时间:07分58秒628 --- 开始计时 -->
D/HIDETAG: <-- 当前时间:07分59秒646 --- 当前计时:5 -->
D/HIDETAG: <-- 当前时间:07分59秒647 --- 当前计时:4 -->
D/HIDETAG: <-- 当前时间:08分00秒646 --- 当前计时:3 -->
D/HIDETAG: <-- 当前时间:08分01秒646 --- 当前计时:2 -->
D/HIDETAG: <-- 当前时间:08分02秒645 --- 当前计时:1 -->
D/HIDETAG: <-- 当前时间:08分03秒646 --- 当前计时:0 -->
D/HIDETAG: <-- 当前时间:08分03秒650 --- 计时完成 -->
WTF……5
与4
怎么同时执行了!反倒是doOnSubscribe()
与计时5
之间有1秒的间隔,很明显有BUG。
这么几行代码找了1个小时没找到问题在哪里……后来尝试着把.subscribeOn(AndroidSchedulers.mainThread())
删除,然后又运行了一下:
D/HIDETAG: <-- 当前时间:14分58秒142 --- 开始计时 -->
D/HIDETAG: <-- 当前时间:14分58秒162 --- 当前计时:5 -->
D/HIDETAG: <-- 当前时间:14分59秒163 --- 当前计时:4 -->
D/HIDETAG: <-- 当前时间:15分00秒150 --- 当前计时:3 -->
D/HIDETAG: <-- 当前时间:15分01秒150 --- 当前计时:2 -->
D/HIDETAG: <-- 当前时间:15分02秒149 --- 当前计时:1 -->
D/HIDETAG: <-- 当前时间:15分03秒150 --- 当前计时:0 -->
D/HIDETAG: <-- 当前时间:15分03秒151 --- 计时完成 -->
居然正确了,倒计时正常工作了……
不知道是Rx
的BUG还是我漏掉了什么知识,为什么指定subscribe
的线程为主线程会导致第一次计时不准确?
希望有知道的不吝赐教。
2016.2.16更新:找到原因了,不是Rx的锅,是我自己编译环境的问题……
网友评论
Observable.interval(0, 1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.take((time + 1).toLong())
.map { along ->
return@map time - along
}
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {
//开始验证码倒计时
}
.subscribe({ num ->
//倒计时过程中
}, {}, {
//倒计时完毕
})
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
TestCount--;
if(TestCount<=0){
if(mDisposable.isDisposed()){
mDisposable.dispose();
}
}else{
Logger.e("-----倒计时"+TestCount);
}
}
});
public void autoJumpDelay() {
final int countTime = 10;
Observable
.interval(0, 1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<Long, Integer>() {
@Override
public Integer call(Long increaseTime) {
return countTime - increaseTime.intValue();
}
})
.take(countTime)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer remainTime) {
System.out.println(remainTime);
mView.startCountdown(remainTime);
}
});
}
@Override
public void startCountdown(final int remainTime) {
tvSkip.setText(
TextUtils.concat(
String.valueOf(remainTime),
" 跳过"
)
);
}
这段代码在Android4.2、5.0上都运行正常,但是在4.3.3上不能正常更新ui
有人能给解决下么?
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
.limit(5)
.map { 5 - it }
.doOnSubscribe { println("开始倒计时") }
.doOnCompleted { println("结束倒计时") }
.subscribe { println("$it") };
运行结果:http://ww2.sinaimg.cn/large/ded3864ejw1f110zlf3jbj216206wad8.jpg