RxJava流程详解

357 阅读10分钟

整体流程

以下面的调用方式为例:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("hello");
                emitter.onNext("world");
                emitter.onComplete();
            }
        }).map(new Function<String, String>() {
            @Override
            public String apply(String s) throws Exception {
                return s + ": after map";
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String s) {
                        Log.d("MainActivity", "这里是onCreate方法:"+s);
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

在上面的调用链中,Observable以及其subscribeActual方法所处理的Observer对象变化流程为:

new ObservableOnSubscribe{ subscribe } -> (ObservableCreate, CreateEmitter) <-> (ObservableMap, MapObserver) <-> (ObsersvableSubscribeOn, SubscribeOnObserver) <-> (ObservableObserveOn, ObserveOnObserver) <- new Observer{ onNext }

从左往右看:前面的Observable为后面的ObservableXX的source属性;从右往左看:前面的Observer为后面的XXObserver的actual属性

上面是以订阅流程中相关对象的变化来看的,他们间的关系并不是处理与被处理的关系,ObservableXX与XXObserver将按照处理关系绑定的话是如下这样:

new ObservableOnSubscribe{ subscribe }.subscribe(CreateEmitter) <- ObservableCreate.subscribe(MapObserver) <- ObservableMap.subscribe(SubscribeOnObserver) <- ObservableSubscribeOn.subscribe(ObserveOnObserver) <- ObservableObserveOn.subscribe(new Observer{ onNext })

以上就是函数传参 -- 真正订阅关系上各个对象的对应关系。

Observable订阅流程

Observable的订阅流程决定着最初的ObservableOnSubscribe中我们初始化的subscribe方法的调用,因此,对Observable来说,要关注其subscribe方法执行逻辑:

// ObservableCreate.java
@Override
    protected void subscribeActual(Observer<? super T> observer) {
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        observer.onSubscribe(parent);

        try {
            // 直接调用
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }

// ObservableMap.java
@Override
    public void subscribeActual(Observer<? super U> t) {
        // 直接调用
        source.subscribe(new MapObserver<T, U>(t, function));
    }

// ObservableSubscribeOn.java
@Override
    public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
        s.onSubscribe(parent);

        // scheduler.scheduleDirect()进行切线程,并且只是将source.subscribe(parent)这一过程封装到了Runnable中
        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

// ObservableObserveOn.java
protected void subscribeActual(Observer<? super T> observer) {
        if (scheduler instanceof TrampolineScheduler) {
            source.subscribe(observer);
        } else {
            Scheduler.Worker w = scheduler.createWorker();

            // 直接调用
            source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
        }
    }

接上文,Observable的subscribeActual方法我们只需要关注source.subscribe()的调用即可,而会影响这一步骤调用的只有ObservableSubscribeOn中会使用Scheduler切线程

还有一个疑惑点是在ObservableSubscribeOn的subscribeActual方法中执行了,s.onSubscribe方法,而此时的s类型为ObserveOnObserver,因此,在ObserveOnObserver中会在当前线程执行actual的onSubscribe方法,而这是正确的;但是,我们知道subscribeActual最终会回传到最初的ObservableCreate的subscribeActual方法中,而这里再一次调用了s.onSubscribe方法,那这会不会导致最初的Observer的onSubscribe方法被调用两次?答案是不会,因此此时的s.onSubscribe方法实现位于SubscribeOnObserver中,我们连看看他的方法实现:

// SubscribeOnObserver.java
@Override
public void onSubscribe(Disposable s) {
    DisposableHelper.setOnce(this.s, s);
}

// DisposableHelper.java
public static boolean setOnce(AtomicReference<Disposable> field, Disposable d) {
    ObjectHelper.requireNonNull(d, "d is null");
    if (!field.compareAndSet(null, d)) {
        d.dispose();
        if (field.get() != DISPOSED) {
            reportDisposableSet();
        }
        return false;
    }
    return true;
}

可见,上述的onSubscribe方法相当于什么事儿都没做,所以Observer的onSubscribe不会被执行两次。因此,在subscribeOn和observeOn的交界处,往后就都是SubscribeOnObserver了,因此,即使调用多次subscribeOn,Observer的onSubscribe也只会执行一次。

Observer处理流程

观察Observer只需要关注其onNext、onComplete、onError回调即可,以下代码仅仅展示onNext:

// CreateEmitter.java
@Override
        public void onNext(T t) {
            ...
            if (!isDisposed()) {
                // 直接调用
                observer.onNext(t);
            }
        }

// MapObserver.java
@Override
        public void onNext(T t) {
            U v;
            try {
                // 先变换
                v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
            } 
            // 直接调用
            actual.onNext(v);
        }

// SubscribeOnObserver.java
@Override
        public void onNext(T t) {
            // 直接调用
            actual.onNext(t);
        }

// ObserveOnObserver.java
@Override
        public void onNext(T t) {
            if (done) {
                return;
            }

            if (sourceMode != QueueDisposable.ASYNC) {
                queue.offer(t);
            }
            // 内部切线程并且回调actual的onNext
            schedule();
        }

可见,Observer在封装过程中,大部分也是直接调用的actual的onNext回调,只有ObserveOnObserver内部会进行线程调度。

subscribeOn如何切换线程

subscribeOn传递的Schedulers.io()负责将Observable.subscribe(Observer)这一动作放在后台线程执行。因此,可以猜测,应该有两步:

  1. 将Observable.subscribe(Observer)包装到一个Runnable中;
  2. 将上述Runnable放入到线程中执行。

接下来就看看是如何做到的:

// ObservableSubscribeOn.java
@Override
    public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);

        // 可以看到onSubscribe回调是在UI线程
        s.onSubscribe(parent);

        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

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

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

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

这里的SubscribeTask是ObservableSubscribeOn的内部类,因此其可以访问到source变量;可以看到,这里正是将source.subscribe(parent)包装到了Runnable中,等待将该Runnable放到线程中执行,第一步已经完成,那么就看看第二步是怎么实现的。

以Schedulers.io()为例,此时的scheduler变量为IOScheduler;而schedulerDirect是父类Scheduler提供的模板方法,在父类中被实现好了:

// Scheduler.java
@NonNull
    public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
        // 此时调用具体子类的createWorker方法
        final Worker w = createWorker();

        // 这里可以忽略,本质还是将参数run进行包装
        final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

        // 再次封装runnable
        DisposeTask task = new DisposeTask(decoratedRun, w);

        // 使用Worker来执行具体的Runnable封装
        w.schedule(task, delay, unit);

        return task;
    }

==Scheduler顾名思义,是一个调度器,调度什么?就是具体动作的线程调度,即从当前线程调度到目标现成,因此,Scheduler并不是执行目标的地方,其通过scheduleDirect方法调度给了Worker去执行目标Runnable。==可以看到,进行了很多封装,首先是使用IOScheduler的createWorker方法创建Worker,然后就是使用worker的schedule执行任务:

// IOScheduler.java
public Worker createWorker() {
        return new EventLoopWorker(pool.get());
    }
    

    static final class EventLoopWorker extends Scheduler.Worker {
        private final CompositeDisposable tasks;
        private final CachedWorkerPool pool;
        private final ThreadWorker threadWorker;

        final AtomicBoolean once = new AtomicBoolean();

        
        @Override
        public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
            if (tasks.isDisposed()) {
                // don't schedule, we are unsubscribed
                return EmptyDisposable.INSTANCE;
            }

            // 根据注释,知道实际的方法实现位于NewThreadWorker
            return threadWorker.scheduleActual(action, delayTime, unit, tasks);
        }
    }

// 关于该类,只需要记住其是  NewThreadWorker的子类,并且没有覆盖任何父类方法即可
static final class ThreadWorker extends NewThreadWorker

至此,还没有发现封装好的Runnable是如何在其他线程执行的秘密,继续来到NewThreadWorker类:

// NewTheadWorker.java
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
        Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

        ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);

        Future<?> f;
        try {
            if (delayTime <= 0) {
                f = executor.submit((Callable<Object>)sr);
            } else {
                f = executor.schedule((Callable<Object>)sr, delayTime, unit);
            }
            sr.setFuture(f);
        } 

        return sr;
    }

而这里的executor正是一个线程池!!到这里我们终于发现了第二步的实现,正是将Runnable放入了线程池中执行。

observeOn如何切换线程

observeOn负责将onNext、onComplete、onError的回调执行线程切换到UI线程,鉴于onNext中的参数变量通常来自于后台线程,所以,除了方法调用涉及到切换线程,onNext的参数也涉及到跨线程传递;为此,可以猜测,observeOn将相关调用切换回UI线程涉及到三步:

  1. 将onNext所需的参数保存到一个容器中;
  2. 将相关调用封装到一个Runnable中等待跨线程调用;
  3. 跨线程调用封装好的Runnable。

那么就来看看RxJava是如何实现的:

// ObservableObserveOn.java
@Override
    protected void subscribeActual(Observer<? super T> observer) {
        ...
        else {
            Scheduler.Worker w = scheduler.createWorker();

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

可以发现,模板类似于ObservableSubscribeOn,也是先根据设置的AndroidScheduler.mainThread()的createWorker创建一个Worker,后续的话将worker传递给了ObserveOnObserver。这点和ObservableSubscribeOn不同了,也对,因为想要封装成Runnablel的回调方法位于Observer中,而ObservableObserveOn的subscribeActual还只是一个订阅动作,不涉及到Observer方法回调的事情。

那么就来看看,ObserveOnObserver是如何实现的:

// ObserveOnObserver.java
SimpleQueue<T> queue;

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

            if (sourceMode != QueueDisposable.ASYNC) {
                // 将主线程回调onNext所需的参数存到了容器queue中
                queue.offer(t);
            }
            schedule();
        }

        @Override
        public void onError(Throwable t) {
            if (done) {
                RxJavaPlugins.onError(t);
                return;
            }
            error = t;
            done = true;
            schedule();
        }

        @Override
        public void onComplete() {
            if (done) {
                return;
            }
            done = true;
            schedule();
        }

这里最值得注意的是onNext方法,我们知道,在上一步中Observable.subscribe(Observer)被调用时,其会在执行线程(即IO线程)调用Observer.onNext方法发送数据,此时在ObserveOnObserver中的onNext方法被调用,其将数据T存入了容器queue中。这正体现了我们猜想中的第一步。

还有一点是,在onNext、onError、onComplete的方法最后,都调用了schedule()方法,就看看该方法是如何实现的:

// ObserveOnObserver.java
final Scheduler.Worker worker;
void schedule() {
            if (getAndIncrement() == 0) {
                worker.schedule(this);
            }
        }

等等?我们一开始的猜想,这里只完成了第一步,还没将以上回调封装为Runnable的,否则如何跨线程执行呢??一个可疑点是,这里worker.schedule传递的是this!!传递的是ObserveOnObserver对象??我们再细看其内部的方法:

// ObserveOnObserver.java
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
    implements Observer<T>, Runnable {

        void drainNormal() {
            ...
            final SimpleQueue<T> q = queue;
            final Observer<? super T> a = actual;

            for (;;) {
                ...
                for (;;) {
                    ...
                    try {
                        // 从容器中取出数据
                        v = q.poll();
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        s.dispose();
                        q.clear();
                        a.onError(ex);
                        worker.dispose();
                        return;
                    }
                    ...
                    a.onNext(v);
                }
                ...
            }
        }


        @Override
        public void run() {
            ...
             else {
                drainNormal();
            }
        }

    }

可以看到,ObserveOnObserver确实是Runnable的实现类,同时其run方法实现中调用的drainNormal方法正式不断的从共享容器中取出数据,然后执行onNext方法,至此,猜想的第二部也已经完成了,即将三个方法的回调封装到Runnable中以供切回到UI线程执行。

回过头来,AndroidScheduler.mainThread()的createWorker实现如下:

// HandlerScheduler.java
private final Handler handler;
public Worker createWorker() {
        return new HandlerWorker(handler);
    }


private static final class HandlerWorker extends Worker {
        private final Handler handler;
        @Override
        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);
            message.obj = this; 
            handler.sendMessageDelayed(message, unit.toMillis(delay));

           ...

            return scheduled;
        }

    }

private static final class ScheduledRunnable implements Runnable, Disposable

到此,也发现了第三部,即worker的schedule会将ObserveOnObserver这个Runnable发送到Handler绑定的线程中执行,那么Handler绑定的是主线程吗?

//AndroidScheduler.java
private static final class MainHolder {

    // 可见,绑定的正式主线程
        static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
    }

    private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
            new Callable<Scheduler>() {
                @Override public Scheduler call() throws Exception {
                    return MainHolder.DEFAULT;
                }
            });

    /** A {@link Scheduler} which executes actions on the Android main thread. */
    public static Scheduler mainThread() {
        return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
    }

Map操作符怎么实现类型转换

source的subscribe方法里面进行onNext方法发送,类型转换的方法位于map参数中,想要实现类型转换,需要捕捉到onNext方法发送的参数,而Observable中onNext方法发送的数据被写在了onSubscribe方法中,是没法拦截的;因此,唯一能够拦截到onNext方法发送的数据的地方只有在Observer的onNext方法接收数据时,因此map操作符发挥作用一定是对Observer进行处理。

// Observable.java
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
        ObjectHelper.requireNonNull(mapper, "mapper is null");
    	// 这里将Observable包装了一下
        return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
    }

// ObservableMap.java
final Function<? super T, ? extends U> function;

    public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
        super(source);
        this.function = function;
    }

这里先包装Observable实属迫不得已,因为,map方法执行的时候,observe方法还没有被执行,因此,此时还无法获取Observer,只能现将Observable包装一次,这样mapper才能够向后传递,直到遇见Observer。接下来看看ObservableMap的订阅方法:

// ObservableMap.java
public void subscribeActual(Observer<? super U> t) {
    // 这里能够获取到Observer了,因此此时才能够将Observer进行包装
        source.subscribe(new MapObserver<T, U>(t, function));
    }

而ObservableMap 的订阅方法就能够获取到Observer了,此时就能够对Observer进行包装了。

// ObservableMap.java
static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
        final Function<? super T, ? extends U> mapper;

        MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
            super(actual);
            this.mapper = mapper;
        }

        @Override
        public void onNext(T t) {
            ...
            U v;

            try {
                // 这里调用mapper的apply方法实现类型的转换
                v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
            } 
            
            // 将类型转换之后的数据发送出去
            actual.onNext(v);
        }

        ...
    }

可见mapper的工作原理是:

  • 先对参数进行mapper转换;
  • 然后调用actual的onNext方法将转换后的数据发送出去。

Disposable机制

有一个问题:当调用了Scheduler.io()之后,那么Disposable如何工作呢?因为任务已经被放到了线程池中执行,此时该如何切断呢?

我们回看一下subscribeOn之后发生了什么:

// ObservableSubscribeOn.java
public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);

        s.onSubscribe(parent);

    // 可见,设置的Disposable是scheduler.scheduleDirect方法的返回值
    // 我们假设这里的Scheduler为IOScheduler
        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

// Scheduler.java
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
        final Worker w = createWorker();

        final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

        DisposeTask task = new DisposeTask(decoratedRun, w);

        w.schedule(task, delay, unit);

    	// 可见返回的Disposable是DisposeTask对象
        return task;
    }

可见,返回的就是一个DisposeTask对象,那么就要看看该对象的定义:

// Scheduler.java
static final class DisposeTask implements Disposable, Runnable, SchedulerRunnableIntrospection {
        final Runnable decoratedRun;
        final Worker w;

        Thread runner;

        DisposeTask(Runnable decoratedRun, Worker w) {
            this.decoratedRun = decoratedRun;
            this.w = w;
        }

        @Override
        public void run() {
            runner = Thread.currentThread();
            try {
                decoratedRun.run();
            } finally {
                dispose();
                runner = null;
            }
        }

        @Override
        public void dispose() {
            // 可见,在Scheduler为IOScheduler的情况下,其Worker就是NewThreadWorker
            // 此时,dispose方法的作用就是执行Worker的shutdown方法
            if (runner == Thread.currentThread() && w instanceof NewThreadWorker) {
                ((NewThreadWorker)w).shutdown();
            } else {
                w.dispose();
            }
        }
    ....
    }

// NewThreadWorker.java
public void shutdown() {
        if (!disposed) {
            disposed = true;
            // 关闭线程池
            executor.shutdown();
        }
    }

可见,在Scheduler为IoScheduler的情况下,获取到的Disposable的dispose方法就是关闭线程池。

问题解答

以以下调用为例:

source.subscribeOn(Scheduler1).subscribeOn(Scheduler2).observeOn(Scheduler.a).observeOn(Scheduler.b).observe(actual)
    
相关对象如下:
Observable:
	source
    observable1 : thread1
    observable2 : thread2

Obeserver:
	observer-a  : thread-a
    observer-b  : thread-b
    actual
        

多次subscribeOn只有第一次生效

在发生subscribe时,observable2的subscribeActual首先被调用,其将source2.subscribe()动作分发到了thread2中执行,注意这里的source2正是observable1;因此,方法调用来到啦observable1的subscribeActual,其将source1.subscribe()动作分发到了thread1中执行,注意这里的source1正是source对象,所以我们在初始化时定义的subscribe实现就是在thread1中被调用,因此说,只有第一次subscribeOn有效。

多次observeOn只有最后一次生效

在发生subscribe时,observer-a的三个方法回调被分发到了thread-a中,从而触发actual-a的三个方法回调,而这里的actual-a正是observer-b对象;因此,方法调用来到了observer-b中,同样,observer-b会将三个方法回调分发到thread-b中执行,从而触发actual-b的三个方法回调,而这里的actual-b正是最终的actual,所以我们在初始化时定义的onNext、onComplete、onError方法正是在thread-b中被调用,因此说,只有最后一次observerOn有效。