RxJava的整个流程分为三个步骤
- 从上到下创建任务链,这里没有涉及线程调度。默认执行在当前线程,在这里也就是主线程。
- 自下向上逆向订阅,这个过程
subscribeOn
起作用,observeOn
不起切换线程作用。 - 从上到下执行,类似
map
中的代码,这时候observeOn
起切换线程作用。
也是为什么subscribeOn
只有第一次起作用,observeOn
每次都起作用。
Q1:为什么 subscribeOn() 只有第一次切换有效
简单分析一下代码执行流程
- 从上到下,建立上下依赖关系,初始化线程
- 从
.subscribe
为调用起点,自下向上开始准备调用,这个过程subscribeOn
起作用,observeOn
不起切换线程作用。 - 从上到下执行,类似
map
中的代码,这时候observeOn
起切换线程作用。
因为 RxJava 最终能影响 ObservableOnSubscribe 这个匿名实现接口的运行环境的只能是最后一次运行的 subscribeOn() ,又因为 RxJava 订阅的时候是从下往上订阅,所以从上往下第一个 subscribeOn() 就是最后运行的,这就造成了写多个 subscribeOn() 只有第一个subscribeOn()有用。
如下图:subscribeOn()产生的线程切换发生在代码执行的第二层,而它的回溯又将会执行在新的线程中。因此,在subscribeOn切换线程以后的流程,均将在新的线程中执行。
observeOn()产生的线程切换都发生在第三层执行层,而在切换线程前的业务代码由于已经执行了,故不受切换线程切换的影响。
Q2:每一次observeOn
的使用,都会将后面的观察者(同上)和将要切换的线程内容封装起来。
每次observeOn
都会切换后面内容的执行线程。
Q3:observeOn() 的线程切换原理
总结:
- 子线程切换主线程:给主线程所在的Handler发消息,然后就把逻辑切换过去了。
- 主线程切换子线程:把任务放到线程池中执行就能把执行逻辑切换到子线程
- 子线程切换子线程:把任务分别扔进两个线程就行了。
Q4:线程控制Scheduler
可以利用 subscribeOn() 结合 observeOn() 来实现线程控制,让事件的产生和消费发生在不同的线程。又知道map(),和flatMap()等可以做不同的变换,那么也可以通过多次地调用函数来实现多次线程的切换
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() 指定