RxJava debounce操作符防止界面刷新过度
条评论有些场景下APP需要根据数据实时刷新界面,数据刷新过快,界面跟着刷新可能会出现界面卡顿的问题。特别是在界面显示的元素比较多绘制时间比较长、刷新界面需要执行动画等情况下,就会导致界面卡顿。刷新过快的时候,中间的一些数据是可以过滤掉,只要根据最后一个数据刷新界面就可以了。
解决这个问题需要分为两个步骤:
- 发射事件:收到数据时,使用同一个
Observable
发送更新事件 - 过滤事件:过滤发射频率过快的数据,处理最后一项即可
发射事件
RxJava 发射事件的方式是通过 subscriber.onNext()
,每调用一次这个方法就会发射一个事件。1
Observable.create(subscriber -> subscriber.onNext("emit"));
将 subscriber
保存为一个全局变量,收到数据时调用subscriber.onNext()
即可发射事件通知刷新界面。1
2
3
4
5
6
7
8
9
10
11
12private Subscriber<? super Object> mSubscribe;
private void initUIObservable() {
Observable.create(subscriber -> mSubscribe = subscriber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(i -> Log.d(TAG,"refresh UI"));
}
private void receiveData() {
mSubscribe.onNext("emit");
}
过滤事件
通过RxJava的操作符 debounce
过滤掉发射速率过快的数据项,防止界面刷新频率过快。
debounce
产生一个新的Observable
,这个Observable
只发射原Observable
中时间间隔小于指定阈值的最大子序列的最后一个元素。 参考资料:Debounce参考资料:Debounce
通过例子看看 debounce
的实际作用。1
2
3
4
5
6
7private void debounceTest() {
Observable.interval(100, TimeUnit.MILLISECONDS)
.filter(i -> i < 6)
.doOnNext(i -> Log.d("RxJava", "emit num :" + i)) // 发射的数字
.debounce(300, TimeUnit.MILLISECONDS)
.subscribe(i -> Log.d("RxJava", "receive num :" + i)); // 接收到的数字
}
输出为:
这里例子中,每100ms发射一个数据,debounce
设置的时间阈值为300,这时 subscribe
只接收到了最后一个事件。
如果把 interval
的时间间隔改成500ms,subscribe
就可以接收到所有事件。
总结
把发射事件和过滤事件结合到一起,即可解决因为数据等原因导致界面刷新过快的问题。整理之后的代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15private Subscriber<? super Object> mSubscribe;
// 初始化界面观察者
private void initUIObservable() {
Observable.create(subscriber -> mSubscribe = subscriber)
.subscribeOn(Schedulers.io())
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(i -> Log.d(TAG,"refresh UI"));
}
// 接收到数据,通知刷新界面
private void receiveData() {
mSubscribe.onNext("emit");
}