1、throttleFirst操作符
该操作符的作用是------在每次事件触发后的一定时间间隔内,常用作去抖动过滤,例如按钮的点击:
RxView.clickEvents(button) // RxBinding 代码,后面的文章有解释 .throttleFirst(500, TimeUnit.MILLISECONDS) // 设置防抖间隔为 500ms .subscribe(subscriber); 妈妈再也不怕我的用户手抖点开两个重复的界面啦。
2、变换的原理:lift()
变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送, 在rxjava内部,他们是基于同一个基础的变换方法,lift(operator),下面是lift的核心代码:
// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
简述原理就是:在observable执行了lift(operator)方法之后,会返回一个新的observable,这个新的observable会像一个代理一样,负责接收原始的observable发出的事件,并在处理后发送给subscriber。
3、compose:对Observable的整体变换
除了lift之外,observable还有一个变换方法叫作compose(Transformer),它和lift的区别在于,lift是针对事件项和事件序列的;而compose是针对observable自身进行变换。
public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
@Override
public Observable<String> call(Observable<Integer> observable) {
return observable
.lift1()
.lift2()
.lift3()
.lift4();
}
}
...
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
observable4.compose(liftAll).subscribe(subscriber4);
4、线程控制Scheduler
通过这个Scheduler可以实现线程的自由切换,subscribeOn() 结合observeOn() 这两个方法可以让事件的产生和消费发生在不同的线程;
可以多次切换线程。下面的例子:
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(mapOperator) // 新线程,由 observeOn() 指定
.observeOn(Schedulers.io())
.map(mapOperator2) // IO 线程,由 observeOn() 指定
.observeOn(AndroidSchedulers.mainThread)
.subscribe(subscriber); // Android 主线程,由 observeOn() 指定
其实,subscribeOn( ) 和ObserveOn( )的内部实现,也是用的lift,
当使用多个subscribeon()的时候,只有第一个subscribeOn()起作用。
延伸:doOnSubscribe()
然而,虽然超过一个subscribeOn()对于事件处理的流程没有影响,
Subscriber中,提到过Subscriber的onstart()方法可以用作流程开始前的初始化,然而由于onStart()方法在subscribe()发生时就被调用了,因此不能指定线程,而是只能执行在subscribe()被调用时的线程,这就导致如果onStart()中含有对线程有要求的代码(例如更新UI的操作不能发生在子线程),将会有线程非法的风险。
而与Subscriber.onStart()相对应的,有一个方法Observable.doOnSubscribe(),它和onstart()一样,也是在subscribe()发生时调用,但是有区别的是,他可以指定线程,默认他会执行在subscribe()发生的线程,而如果在doOnSubscribe()之后有subscribeOn(),那么他将执行在离他最近的subscribeOn()指定的线程。
实例代码:
Observable.create(onSubscribe)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
@Override
public void call() {
progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
}
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);