RxJava切换线程是怎么实现的呢?
lift变换过程
要明白 RxJava 切换线程切换线程的原理,我们首先得理解变换过程。
对于变换过程,我的理解就是:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
})
.observeOn(Schedulers.io())
.map(new Function<String, List<String>>() {
@Override
public List<String> apply(String query) {
return mCheeseSearchEngine.search(query);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(List<String> result) {
showResult(result);
}
});
在上面的代码中,map 过程通过它的 apply 方法中把 String 转换为 List\ ,而这一点是 subscribe 无法做到的。
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return lift(new OperatorMap<T, R>(func));
}
通过 map函数 的源码我们可以看出 map 函数直接调用了 lift 函数并且把我们的 func 传了进去,而 func 就是我们所做的具体变换操作。
// 注意:这段代码被我修改过部分参数,仅用于理解,源码并非如此。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable2.create(new OnSubscribe2<R>() {
@Override
public void call(Subscriber subscriber1) {
Subscriber subscriber2 = operator.call(subscriber1);
subscriber2.onStart();
onSubscribe1.call(subscriber2);
}
});
}
我们可以看到这里我们又创建了一个新的 Observable 对象,我们记为 Observable2,也就是说当我们执行 map 时,实际上返回了一个新的 Observable 对象,我们之后的 subscribe 函数实际上执行再我们新创建的 Observable2 上,这时他调用的就是我们新的 call 函数,也就是 Observable2 的 call 函数。最后 onSubscribe1.call(subscriber2) 的 onSubscribe1 就是我们 Observable1(原来的Observable) 保存的 onSubscribe1 对象,在OnSubscrib1中做一些回调操作,如subscriber2.next()。
接着我们看operator.call(subscriber1)的过程。
// 注意:这段代码也被我修改过。
public Subscriber<? super T> call(final Subscriber<? super R> subscriber1) {
return new Subscriber2<T>(subscriber1) {
@Override
public void onNext(T t) {
subscriber1.onNext(transformer.call(t));
}
};
}
这里的 transformer 就是我们在 map 调用是传进去的 func 函数,也就是变换的具体过程。到这里变换过程就此结束。我们总结一下,
如图所示,实际上我们通过 lift 创建了一个新的对象 Observable2 ,我们之后的 subscribe 实际上执行在了它身上。operator执行了之前 Observable1 的 call 函数,并且创建了一个新的对象 Subscriber2 ,它的作用就是接受原来 Observable1 的事件 func ,然后经过转换,传递给最终的 Subscriber1,执行它的 onNext 函数。我们这样就跑通了变换的整个逻辑了,我们也可以发现这个逻辑类似于拦截,通过拦截 subscribe 函数,再把 Observable1 的 subscribe 拦截到新的 Subscriber2 对象中来执行,从而实现转换的逻辑。
线程切换
RxJava 最好用的特点就是��供了方便的线程切换,但它的原理归根结底还是 lift。subscribeOn() 和 observeOn() 都做了线程切换的工作(图中的 “schedule…” 部位)。不同的是, subscribeOn() 的线程切换发生在 OnSubscribe 中,即在它通知上一级 OnSubscribe 时,这时事件还没有开始发送,因此 subscribeOn() 的线程控制可以从事件发出的开端就造成影响。
![](http://p66upaccy.bkt.clouddn.com/15243990563460.jpg)
为什么 subscribeOn()只有第一个有效?
举个例子,subscribeOn2从通知开始将后面的执行全部投递到需要的线程2来执行,但是之后的投递会受到在subscribeOn2的上级subscribeOn1的的影响,subscribeOn1又会把执行投递到线程1中去,这样执行就不受到subscribeOn2的控制了。所以只有第一个subscribeOn有效。
图中共有 5 处含有对事件的操作。由图中可以看出,①和②两处受第一个 subscribeOn() 影响,运行在红色线程;③和④处受第一个 observeOn() 的影响,运行在绿色线程;⑤处受第二个 onserveOn() 影响,运行在紫色线程;而第二个 subscribeOn() ,由于在通知过程中线程就被第一个 subscribeOn() 截断,因此对整个流程并没有任何影响。这里也就回答了前面的问题:当使用了多个 subscribeOn() 的时候,只有第一个 subscribeOn() 起作用。