前言
在上一篇博客 Rxjava 源码系列 - 基础框架分析,我们分析了 Rxjava 的基础框架。
Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer,并且回调 Observer 的相应的方法。
用一张简单的流程图描述如下:
Observable#subscribeOn
在 Android 中,我们知道默认都是执行在主线程的,那么 Rxjava 是如何实现线程切换的。
1Observable.create(new ObservableOnSubscribe<String>() { 2 @Override 3 public void subscribe(ObservableEmitter<String> emitter) throws Exception { 4 emitter.onNext("1"); 5 emitter.onNext("2"); 6 emitter.onNext("3"); 7 emitter.onComplete(); 8 } 9 })10 .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<String>() {11 @Override12 public void onSubscribe(Disposable d) {13 Log.e("TAG", "onSubscribe(): ");14 }1516 @Override17 public void onNext(String s) {18 Log.e("TAG", "onNext(): " + s);19 }2021 @Override22 public void onError(Throwable e) {2324 }2526 @Override27 public void onComplete() {28 Log.e("TAG", "onComplete(): ");29 }30 });
我们先来看一下 subscribeOn 方法,可以看到
1@CheckReturnValue2@SchedulerSupport(SchedulerSupport.CUSTOM)3public final Observable<T> subscribeOn(Scheduler scheduler) {4 // scheduler 判空5 ObjectHelper.requireNonNull(scheduler, "scheduler is null");6 // 用 ObservableSubscribeOn 将 scheduler 包装 起来7 return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));8}
而我们从上一篇博客中知道,当我们调用 observable.subscibe(observable) 的时候,最终会调用到具体的 observable 的实例的 subscribActual 方法。而这里具体的 observable 的实例为 ObservableSubscribeOn。
接下来,我们来看一下 ObservableSubscribeOn 这个类,可以看到继承 AbstractObservableWithUpstream ,而 AbstractObservableWithUpstream 继承 Observable,实现 HasUpstreamObservableSource 这个接口。
1public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> { 2 final Scheduler scheduler; 3 4 public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) { 5 super(source); 6 this.scheduler = scheduler; 7 } 8 9 @Override10 public void subscribeActual(final Observer<? super T> s) {11 final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);1213 s.onSubscribe(parent);1415 parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));16 }1718 ---19}202122abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {2324 /** The source consumable Observable. */25 protected final ObservableSource<T> source;2627 /**28 * Constructs the ObservableSource with the given consumable.29 * @param source the consumable Observable30 */31 AbstractObservableWithUpstream(ObservableSource<T> source) {32 this.source = source;33 }3435 @Override36 public final ObservableSource<T> source() {37 return source;38 }3940}4142public interface HasUpstreamObservableSource<T> {43 /**44 * Returns the upstream source of this Observable.45 * <p>Allows discovering the chain of observables.46 * @return the source ObservableSource47 */48 ObservableSource<T> source();49}
observableSubscribeOn 的 subscribeActual 方法,跟 ObservableCreate 的 subscribeActual 的套路差不多,它也是 Observable 的一个子类。只不过比 ObservableCreate 多实现了一个接口HasUpstreamObservableSource,这个接口很有意思,他的 source() 方法返回类型是 ObservableSource(还记得这个类的角色吗?)。也就是说 ObservableSubscribeOn 这个 Observable 是一个拥有上游的 Observable 。他有一个非常关键的属性 source,这个 source 就代表了他的上游。
接下来我们一起来看一下 ObservableSubscribeOn 的具体实现
1public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> { 2 final Scheduler scheduler; 3 4 public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) { 5 super(source); 6 this.scheduler = scheduler; 7 } 8 9 @Override10 public void subscribeActual(final Observer<? super T> s) {11 final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);1213 s.onSubscribe(parent);1415 parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));16 }17}
首先先来看他的构造函数 ,有两个参数 source ,scheduler。
-
source 代表上游的引用,是 Observable 的一个实例
-
scheduler 可以通过 Schedulers.newThread() 或者 Schedulers.io() 创建相应的实例
这里我们先大概了解一下 Scheduler 是个什么东东,Scheduler 里面封装了 Worker 和 DisposeTask,下面会详细讲到。
Schedulers.newThread()
1@NonNull 2public static Scheduler newThread() { 3 return RxJavaPlugins.onNewThreadScheduler(NEW_THREAD); 4} 5 6 7NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new NewThreadTask()); 8static final class NewThreadTask implements Callable<Scheduler> { 9 @Override10 public Scheduler call() throws Exception {11 return NewThreadHolder.DEFAULT;12 }13}14static final class NewThreadHolder {15 static final Scheduler DEFAULT = new NewThreadScheduler();16}
1public static Scheduler io() { 2 return RxJavaPlugins.onIoScheduler(IO); 3} 4 5IO = RxJavaPlugins.initIoScheduler(new IOTask()); 6 7static final class IOTask implements Callable<Scheduler> { 8 @Override 9 public Scheduler call() throws Exception {10 return IoHolder.DEFAULT;11 }12}13static final class IoHolder {14 static final Scheduler DEFAULT = new IoScheduler();15}16static final class IoHolder {17 static final Scheduler DEFAULT = new IoScheduler();18}
我们再回到 ObservableSubscribeOn 的 subscribeActual 方法,在上一篇博客的时候已经讲解 Observable 和 Observer 之间是怎样实现订阅关系的,这里就不再具体展开了。
接下来,我们重点关注这一行代码
1 parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
我们先来看一下 SubscribeTask 这个类,他是 ObservableSubscribeOn 的一个非静态内部类,可以看到 其实也比较简单,他实现了 Runnable 接口,并且持有 parent 引用。
1final class SubscribeTask implements Runnable { 2 private final SubscribeOnObserver<T> parent; 3 4 SubscribeTask(SubscribeOnObserver<T> parent) { 5 this.parent = parent; 6 } 7 8 @Override 9 public void run() {10 source.subscribe(parent);11 }12}
然后在 run 方法中,通过 source.subscribe(parent) 建立联系。因而,当我们的 SubscribeTask 的 run 方法运行在哪个线程,相应的 observer 的 subscribe 方法就运行在哪个线程。
这里可能会有人有疑问,SubscribeTask 没有 source 属性,它是怎么访问到 ObservableSubscribeOn 的属性的。
我们知道 java 中,非静态内部类默认持有外部类的引用,因而他可以正常访问外部类 ObservableSubscribeOn 的 source 属性。
接着,我们再来看一下 scheduler.scheduleDirect 这个方法
1@NonNull 2public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) { 3 final Worker w = createWorker(); 4 5 // 判断 run 是否为 null 6 final Runnable decoratedRun = RxJavaPlugins.onSchedule(run); 7 8 DisposeTask task = new DisposeTask(decoratedRun, w); 910 w.schedule(task, delay, unit);1112 return task;13}
-
首先,创建一个 Worker w
-
第二步,DisposeTask 将 decoratedRun 包装起来
-
第三步:w 去调度 task
这里我们以 NewThreadScheduler 为例,来看看这个 Worker 到底是什么?
1public Worker createWorker() { 2 return new NewThreadWorker(threadFactory); 3} 4 5 6 7public class NewThreadWorker extends Scheduler.Worker implements Disposable { 8 private final ScheduledExecutorService executor; 910 volatile boolean disposed;1112 public NewThreadWorker(ThreadFactory threadFactory) {13 executor = SchedulerPoolFactory.create(threadFactory);14 }1516 --- 17}181920public static ScheduledExecutorService create(ThreadFactory factory) {21 final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, factory);22 if (PURGE_ENABLED && exec instanceof ScheduledThreadPoolExecutor) {23 ScheduledThreadPoolExecutor e = (ScheduledThreadPoolExecutor) exec;24 POOLS.put(e, exec);25 }26 return exec;27}
从上面可以看到,其实 worker 里面封装了 executor(线程池),看到这里,相信你也基本明白 Rxjava 线程切换的原理了,其实很简单。
在 ObservableSubscribeOn subscribeActual 方法中, SubscribeTask 包装 parent(SubscribeOnObserver ,包装了 Observer),SubscribeTask 实现了 Runnable 接口,在 run 方法里面调用了 source.subscribe(parent),因而 run 方法所执行的线程将由 worker 决定。这就是 下游决定上游 observable 执行线程的原理。
接下来我们再来看一下:DisposeTask
1static final class DisposeTask implements Disposable, Runnable, SchedulerRunnableIntrospection { 2 final Runnable decoratedRun; 3 final Worker w; 4 5 Thread runner; 6 7 DisposeTask(Runnable decoratedRun, Worker w) { 8 this.decoratedRun = decoratedRun; 9 this.w = w;10 }1112 @Override13 public void run() {14 runner = Thread.currentThread();15 try {16 decoratedRun.run();17 } finally {18 dispose();19 runner = null;20 }21 }2223 @Override24 public void dispose() {25 if (runner == Thread.currentThread() && w instanceof NewThreadWorker) {26 ((NewThreadWorker)w).shutdown();27 } else {28 w.dispose();29 }30 }3132 @Override33 public boolean isDisposed() {34 return w.isDisposed();35 }3637 @Override38 public Runnable getWrappedRunnable() {39 return this.decoratedRun;40 }41 }42}
1// 将 新的 Disposable 设置给 parent ,方便取消订阅关系,2//(因为我们对 Observer 进行相应的包装,原来的 parent 的 Disposable 已经不能代表最新的 Disposable)3parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
DisposeTask 实现了 Disposable,Runnable ,SchedulerRunnableIntrospection 接口,Disposable 接口主要是用来取消订阅关系的 Disposable。
Observable#subscribeOn(Scheduler) 第一次有效原理
1Observable.create(new ObservableOnSubscribe<String>() { 2 @Override 3 public void subscribe(ObservableEmitter<String> emitter) throws Exception { 4 Log.i(TAG, "subscribe: getName=" +Thread.currentThread().getName()); 5 emitter.onNext("1"); 6 emitter.onNext("2"); 7 emitter.onNext("3"); 8 emitter.onComplete(); 9 }10 }) // 进行两次 subscribeOn11 .subscribeOn(Schedulers.io()).subscribeOn(Schedulers.computation()).subscribe(new Observer<String>() {12 @Override13 public void onSubscribe(Disposable d) {14 Log.e("TAG", "onSubscribe(): ");15 }1617 @Override18 public void onNext(String s) {19 Log.e("TAG", "onNext(): " + s);20 }2122 @Override23 public void onError(Throwable e) {2425 }2627 @Override28 public void onComplete() {29 Log.e("TAG", "onComplete(): ");30 }31 });
subscribe: getName=RxCachedThreadScheduler-1
如果将上述的 subscribeOn 的顺序置换
1subscribeOn(Schedulers.computation()).subscribeOn(Schedulers.io())
那么将打印出
subscribe: getName=RxComputationThreadPool-1
为什么是第一次 Observable#subscribeOn(Scheduler) 才有效呢?
前面我们分析到,Observable#subscribeOn(Scheduler) 实际上是将 Observable#subscribe(Observer) 的操作放在了指定线程,当我们调用 subcribe 的时候,它的过程是从下往上的,即下面的 Observable 调用上面的 Observanle。
所以对于我们上面的第一个例子,他的调用流程是这样的:第三个 Observable 调用 Observable#subscribe(Observer) 启动订阅,在其内部会激活第二个 Observable 的 Observable#subscribe(Observer) 方法,但是此时该方法外部被套入了一个 Schedulers.computation() 线程
于是这个订阅的过程就被运行在了该线程中。用伪代码演示如下
1public class Observable { 2 // 第「二」个 Observable 3 Observable source; 4 Observer observer; 5 6 public Observable(Observable source, Observer observer) { 7 this.source = source; 8 this.observer = observer; 9 }1011 public void subscribe(Observer Observer) {12 new Thread("computation") {13 @Override14 public void run() {15 // 第「二」个 Observable 订阅16 source.subscribe(observer);17 }18 }19 }20}
再往上走,第二个 Observable 订阅内部会激活第一个 Observable 的 Observable#subscribe(Observer) 方法,同样的,该方法被套在了 Schedulers.io() 线程中,用伪代码演示
1public class Observable { 2 // 第「一」个 Observable 3 Observable source; 4 Observer observer; 5 6 public Observable(Observable source, Observer observer) { 7 this.source = source; 8 this.observer = observer; 9 }1011 public void subscribe(Observer Observer) {12 new Thread("io") {13 @Override14 public void run() {15 // 第「一」个 Observable 订阅16 source.subscribe(observer);17 }18 }19 }20}
此时到达第一个 Observable 了之后就要开始发射事件了,此时的执行线程很明显是 io 线程。还可以换成 Thread 伪代码来表示。
1new Thread("computation") { 2 @Override 3 public void run() { 4 // 第二个 Observable.subscribe(Observer) 的实质 5 // 就是切换线程,效果类似如下 6 new Thread("io") { 7 @Override 8 public void run() { 9 // 第一个 Observable.subscribe(Observer) 的实质10 // 就是发射事件11 System.out.println("onNext(T)/onError(Throwable)/onComplete() 的执行线程是:" + Thread12 .currentThread().getName());13 }14 } .start();15 }16} .start();
总结
用流程图描述如下:
推荐阅读
RecyclerView addItemDecoration 的妙用 - item 间距平均分布和添加分割线
自定义 behavior - 完美仿 QQ 浏览器首页,美团商家详情页
扫一扫,欢迎关注我的公众号。如果你有好的文章,也欢迎你的投稿。