前言

最近跟朋友聊天,聊到了最近面试的高频题目就聊到了RxJava 的线程切换原理。我们Android 开发大部分应该 RxJava 都用的很6,RXJava + Retrofit + OkHttp 大礼包都用的贼6。自从用了 RxJava 之后 ,Handler 和 SyncTask 基本消失在日常代码中啦。所以本篇就从源码的角度分析 RxJava 线程切换的原理。

注意
本篇的源码基于 RxJava 3.0.7, RxAndroid 3.0.0。还得配置基于JAVA8,否则会报错,因为RxAndroid 中的 AndroidSchedulers 用了 Lambada 表达式。

一、先来看一个实例

这里默认大家都会 RxJava 切换线程啦。为了更加清晰的分析,我将线程切换的代码拆开来写啦。

1. 被订阅者 Observable 如下:

Observable<Integer> createOb = Observable.create(new ObservableOnSubscribe<Integer>() {

                    @Override
                    public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                        Log.e("RX_JAVA", "subscribe threadName = " + Thread.currentThread().getName());
                        emitter.onNext(1);
                        emitter.onNext(2);
                        emitter.onComplete();
                    }
                });

2. 切换到工作(子)线程

ObservableSubscribeOn 是 Observable 的子类

ObservableSubscribeOn<Integer> ioSchedulerOb = (ObservableSubscribeOn<Integer>) createOb
                        .subscribeOn(Schedulers.io());

subscribeOn 方法如下:

public final Observable<T> subscribeOn(@NonNull Scheduler scheduler) {
        Objects.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<>(this, scheduler));
    }

ObservableSubscribeOn 构造函数的传参 scheduler 表示的就是 IoScheduler ,这里就不详细说明原因了,很简单 去 Schedulers.io() 跟进去即可发现:

3. 切换到主线程

ObservableObserveOn<Integer> mainOb = (ObservableObserveOn<Integer>) ioSchedulerOb
                        .observeOn(AndroidSchedulers.mainThread());
3.1. AndroidSchedulers.mainThread() 如下:
public static Scheduler mainThread() {
     return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
 }

继续跟进去 可以发现 切换到主线程的 Scheduler 是 HandlerScheduler,如下:

static final Scheduler DEFAULT
            = new HandlerScheduler(new Handler(Looper.getMainLooper()), true);
  1. 可以看到 Handler 获取了主线程的 Looper,即处理的消息是在主线程中执行的;
  2. true,表示的是消息是异步消息。
3.2 observeOn 方法

最终调用的代码是:RxJavaPlugins.onAssembly(new ObservableObserveOn<>(this, scheduler, delayError, bufferSize));

看看 ObservableObserveOn 的构造函数:

public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
        super(source);
        this.scheduler = scheduler;
        this.delayError = delayError;
        this.bufferSize = bufferSize;
    }

这里面的 source 在我所在代码中指的就是 ObservableSubscribeOn ,因为 我这是 ioSchedulerOb (ObservableSubscribeOn调用的 observeOn 方法。

scheduler 就是之前说的 HandlerScheduler

其他2个参数不在本次分析之中。

4. 订阅者 Observer

Observer<Integer> observer = new Observer<Integer>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("RX_JAVA", "onSubscribe threadName = " + Thread.currentThread().getName());
                        try {
                            Thread.sleep(1_000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onNext(@NonNull Integer integer) {
                        Log.e("RX_JAVA", "integer = " + integer + ", threadNmae = " + Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("RX_JAVA", "onError");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("RX_JAVA", "onComplete");
                    }
                };

5. 订阅

mainOb.subscribe(observer);

注意:

  1. 之所以将切成线程转换成各自的 Observable 是为了便于理解。

二、订阅的源码分析:

public final void subscribe(@NonNull Observer<? super T> observer) {
        Objects.requireNonNull(observer, "observer is null");
        try {
            observer = RxJavaPlugins.onSubscribe(this, observer);

            Objects.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null Observer. Please change the handler provided to RxJavaPlugins.setOnObservableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");

            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
          。。。
        }
    }

observable的订阅方法关键一句subscribeActual(observer),这里提一句,所有的被观察者的订阅入口都是subscribeActual方法,而subscribeActual在被观察者中是抽象方法,因此看对应的observable子类实现的逻辑。

这里由于已经切换到主线程的 Observable 即 调用的是 ObservableObserveOnsubscribeActual 方法如下:

protected void subscribeActual(Observer<? super T> observer) {
    // 上面分析了 scheduler 是 HandlerScheduler,所以条件不满足
        if (scheduler instanceof TrampolineScheduler) {
            source.subscribe(observer);
        } else {
            Scheduler.Worker w = scheduler.createWorker();

            source.subscribe(new ObserveOnObserver<>(observer, w, delayError, bufferSize));
        }
    }

这里 主要分析 2个方法 scheduler.createWorker()source.subscribe(new ObserveOnObserver<>(observer, w, delayError, bufferSize));

2.1 scheduler.createWorker() 方法
public Worker createWorker() {
        return new HandlerWorker(handler, async);
    }

HandlerWorker 是 HandlerScheduler 的内部类,这里暂且不表。

2.2 source.subscribe(observer)

上面分析了 source 指的是 ObservableSubscribeOn,所以调用 ObservableSubscribeOn 中的 subscribe 方法。

observerObservableObserveOn的内部类 ObserveOnObserver

ObservableSubscribeOn 中没有重写 subscribe 方法,所以调用的就是 Observable 的 subscribe 跟前面的一样,主要代码就是 subscribeActual(observer);

public final void subscribe(@NonNull Observer<? super T> observer) {
        Objects.requireNonNull(observer, "observer is null");
        try {
          。。。
            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
            。。。
        }
    }

由于此时的 Observable 是 ObservableSubscribeOn ,所以走到 ObservableSubscribeOn 的 subscribeActual 方法:

@Override
public void subscribeActual(final Observer<? super T> observer) {
// SubscribeOnObserver 是 ObservableSubscribeOn 的内部类 ObserveOnObserver
  final SubscribeOnObserver<T> parent = new SubscribeOnObserver<>(observer);
// observer 就是前面说的 ObservableObserveOn 内部类 ObserveOnObserver
  observer.onSubscribe(parent);
  parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
 }

这里面 有2个方法需要注意:

1. observer.onSubscribe(parent);

即调用的是 ObservableSubscribeOn 的内部类 ObserveOnObserver 的 onSubscribe方法:

public void onSubscribe(Disposable d) {
            if (DisposableHelper.validate(this.upstream, d)) {
                this.upstream = d;
                。。。
                queue = new SpscLinkedArrayQueue<>(bufferSize);

                downstream.onSubscribe(this);
            }
        }

downstream 就是我开始订阅的 Observer:

Observer<Integer> observer = new Observer<Integer>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("RX_JAVA", "onSubscribe threadName = " + Thread.currentThread().getName());
                        try {
                            Thread.sleep(1_000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onNext(@NonNull Integer integer) {
                        Log.e("RX_JAVA", "integer = " + integer + ", threadNmae = " + Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("RX_JAVA", "onError");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("RX_JAVA", "onComplete");
                    }
                };

即 执行上面的 onSubscribe 方法 ,打印结果如下:

Android Rxjava 线程切换的源码分析 rxjava线程切换原理面试_RxJava 线程切换

2. scheduler.scheduleDirect(new SubscribeTask(parent))

SubscribeTask 也是 ObservableSubscribeOn 的内部类,如下:

final class SubscribeTask implements Runnable {
        private final SubscribeOnObserver<T> parent;

        SubscribeTask(SubscribeOnObserver<T> parent) {
            this.parent = parent;
        }

        @Override
        public void run() {
            source.subscribe(parent);
        }
    }

scheduler.scheduleDirect(Runnable run) 的作用其实就是将 run 提交到线程池中去执行,这样就相当于把线程切换到 工作线程 了。这里面就不展开了。

最终会执行 SubscribeTask 中的 run 方法,即 source.subscribe(parent),这里面的source 指的是 ObservableCreate, 因为 在前面的测试代码中 创建 切换到 io 线程的Observable 是 createOb .subscribeOn(Schedulers.io()), 而 createOb 有是通过 Observable.create创建的,看看 Observable.create 的代码如下:

public static <T> Observable<T> create(@NonNull ObservableOnSubscribe<T> source) {
        Objects.requireNonNull(source, "source is null");
        return RxJavaPlugins.onAssembly(new ObservableCreate<>(source));
    }

source.subscribe 最终会调用的是 ObservableCreatesubscribeActual(observer)方法,其中的 observer 就是 SubscribeOnObserver 的内部类 SubscribeOnObserver

protected void subscribeActual(Observer<? super T> observer) {
     //  observer 就是 SubscribeOnObserver 的内部类 SubscribeOnObserver
        CreateEmitter<T> parent = new CreateEmitter<>(observer);
        
        observer.onSubscribe(parent); // 1

        try {
            source.subscribe(parent); // 2
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }

注1 : 执行的就是 SubscribeOnObserver 内部类SubscribeOnObserver的 onSubscribe 方法:

public void onSubscribe(Disposable d) {
       // 设置 Disposable 
            DisposableHelper.setOnce(this.upstream, d);
        }

注2 : source.subscribe(parent)

parent 就是 ObservableCreate 内部类 CreateEmitter

这里面的 source就是我在测试代码中传进去的,如下:

Observable<Integer> createOb = Observable.create(new ObservableOnSubscribe<Integer>() {

      @Override
        public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
           Log.e("RX_JAVA", "subscribe threadName = " + Thread.currentThread().getName());
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onComplete();
            }
          });

执行的结果如下:

Android Rxjava 线程切换的源码分析 rxjava线程切换原理面试_RxJava 线程切换_02


然后 里面执行发射器的发射, 即调用 ObservableCreate 中的 内部类 CreateEmitter 的 onNext 方法:

public void onNext(T t) {
            if (t == null) {
                onError(ExceptionHelper.createNullPointerException("onNext called with a null value."));
                return;
            }
            if (!isDisposed()) {
                observer.onNext(t);
            }
        }

observer.onNext(t) 调用的就是 ObservableSubscribeOn 内部类 SubscribeOnObserver 的 onNext 方法。

最终调用的是 ObservableObserveOn的内部类 ObserveOnObserver 的onNext 方法:

public void onNext(T t) {
            if (done) {
                return;
            }

            if (sourceMode != QueueDisposable.ASYNC) {
                queue.offer(t);
            }
            schedule();
        }

schedule() 如下:

void schedule() {
            if (getAndIncrement() == 0) {
                worker.schedule(this);
            }
        }

worker.schedule(this) 最终调用的是 HandlerScheduler 中的 schedule,如下:

public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
          。。。
          run = RxJavaPlugins.onSchedule(run);
          
          ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
  
          Message message = Message.obtain(handler, scheduled); // 注2
          message.obj = this; // Used as token for batch disposal of this worker's runnables.

          if (async) {
              message.setAsynchronous(true);
          }

         handler.sendMessageDelayed(message, unit.toMillis(delay));
         。。。
         return scheduled;
        }

注1 : Message message = Message.obtain(handler, scheduled)

这里是利用 Message的obtain来回收利用消息,代码如下:

public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

把 scheduled 方法设置为 Message 的 callback,我们知道给Message 设置了 callback后,那么通过 Handler发送消息后,执行的就是这个 callback 而不是 handler 的 handleMessage 方法。Handler 中 dispatchMessage 方法如下

public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

注2 : 就是发送一个延时消息,没啥好说的。

那么消息发送后,消息的执行最终调用的就是 ObservableObserveOn 中内部类 ObserveOnObserverrun 方法:

public void run() {
            if (outputFused) {
                drainFused();
            } else {
                drainNormal();
            }
        }

最终调用的是 drainNormal()

void drainNormal() {
            int missed = 1;

            final SimpleQueue<T> q = queue;
            final Observer<? super T> a = downstream;

            for (;;) {
                if (checkTerminated(done, q.isEmpty(), a)) {
                    return;
                }

                for (;;) {
                   。。。
                    a.onNext(v);
                }

                missed = addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }

最终调用的 a.next(),注意的是此时已经切到主线程了,是通过 Handler 实现的。这里的a 就是 测试代码中 订阅的 observer

Observer<Integer> observer = new Observer<Integer>() {
 @Override
 public void onSubscribe(@NonNull Disposable d) {
    Log.e("RX_JAVA", "onSubscribe threadName = " + Thread.currentThread().getName());
         try {
              Thread.sleep(1_000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
               }
             }
   
         @Override
         public void onNext(@NonNull Integer integer) {
           Log.e("RX_JAVA", "integer = " + integer + ", threadNmae = " + Thread.currentThread().getName());
           }
   
        @Override
        public void onError(@NonNull Throwable e) {
          Log.e("RX_JAVA", "onError");
         }
         
         @Override
          public void onComplete() {
              Log.e("RX_JAVA", "onComplete");
          }
   };

打印结果如下:

Android Rxjava 线程切换的源码分析 rxjava线程切换原理面试_内部类_03


最后给出一个流程图,如下:

Android Rxjava 线程切换的源码分析 rxjava线程切换原理面试_ide_04