阅读 3499

RxJava3 源码分析 一 分析流式结构与线程调度

一、从比较简单的Single入手,一步步分析总结

下面是一段基于RxJava3的简单任务创建&Map操作符示例

        Single.just(1)
                .subscribeOn(Schedulers.io())
                .map(object:Function<Int,String>{
                    override fun apply(t: Int?): String {
                        Thread.sleep(2000)
                        return t.toString()
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object:SingleObserver<String>{
                    override fun onSuccess(t: String?) {
                    }
                    override fun onSubscribe(d: Disposable?) {
                    }
                    override fun onError(e: Throwable?) {
                    }
                })
复制代码

在io线程睡2s再将数字转换为String返回,并在ui主线程收到这个string值。为了方便阅读 就不做lambda简化了。

二、首先,为什么这代码如此“流式”?

因为从just开始一直到observeOn这四个方法返回的都是 Single 有一点点像Builder模式的感觉,只是感觉哈,就是能一直...,如果不这么玩有其他办法?有的,比如使用地狱回调嵌套。

这里需要提一下:Rxjava是采用了响应式编程的思想[采用生产者/消费者模型]同时提供良好API调用体验的一个封装库,或者叫线程工具。

三、线程切换怎么切换的

因为已经分析过有理解,就不记录那些绕弯子的过程了。直接从最下面往上读源码,并用最直白的易懂的逻辑描述出来,毕竟说不出来的知识是“假知识”。

  • 1 subscribe方法,这方法传递进去了一个SingleObserver,用于接受回调通知。

追这个方法,一直追会看到实际内部是调用 subscribeActual方法,这个方法也是Single的哦,因为上面每个操作都返回的Single嘛。

    public final void subscribe(@NonNull SingleObserver<? super T> observer) {
...
        try {
            subscribeActual(observer);
...
        }
    }
复制代码
  • 2 接着看创建这个observer的方法的observeOn方法,注意外面传递进去了一个mainThread调度器,这个很关键,一定要记住此时传进去的。
    public final Single<T> observeOn(@NonNull Scheduler scheduler) {
        Objects.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new SingleObserveOn<>(this, scheduler));
    }

复制代码

可以看到创建了SingleObserveOn返回,并且传递进去了this,和scheduler。这里又要敲黑板了,this是谁?scheduler是谁? this就是调用这个方法对象,就是上一个方法的返回对象即map的。 scheduler呢,就是mainThread。 看一下mainThread是个什么,

public final class AndroidSchedulers {

    private static final class MainHolder {
        static final Scheduler DEFAULT
            = new HandlerScheduler(new Handler(Looper.getMainLooper()), true);
    }

    private static final Scheduler MAIN_THREAD =
        RxAndroidPlugins.initMainThreadScheduler(() -> MainHolder.DEFAULT);

    public static Scheduler mainThread() {
        return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
    }
...
复制代码

哦创建了一个封装的HandlerScheduler传递进去了一个由MainLooper 构建的Handler,啊好像明白了什么又说不出来。先不急等会儿再过来看,因为还没到他执行 这里只要知道他是个什么类型,方便一会儿找到他。

  • 3 回到上面执行位置,继续看 observeOn()接受this与scheduler的对象

SingleObserveOn 关注点当然是subscribeActual方法啦,因为上面分析过,每个Single订阅执行的都是这个方法。 SingleObserveOn 的SingleObserveOn方法

public final class SingleObserveOn<T> extends Single<T> {

    final SingleSource<T> source;

    final Scheduler scheduler;

    public SingleObserveOn(SingleSource<T> source, Scheduler scheduler) {
        this.source = source;
        this.scheduler = scheduler;
    }

    @Override
    protected void subscribeActual(final SingleObserver<? super T> observer) {
        source.subscribe(new ObserveOnSingleObserver<>(observer, scheduler));
    }
    ...先省略
复制代码

这里也很关键哦,source就是上游Single对象,就是前面敲黑板记的this。 可以看到这里创建了一个内部的observer,并订阅给上游用于接收上游的回调。 而此时在SingleObserveOn中的subscribeActual接收的SingleObserver 是谁呢?就是它嘛subscribe(object:SingleObserver{}就是开发者关注的最终观察者。可以看到这里将下游观察者传递给了内部观察者。

  • 4 既然是内部创建新的观察者订阅给上游,那这个内部观察者肯定会在上游回调后执行。也就是接收上游的参数传递后执行自己的逻辑。那这里可以先不看上游,就先看他自己是如何回调给自己的下游的。好绕啊,好多游啊

!长代码警告!

static final class ObserveOnSingleObserver<T> extends AtomicReference<Disposable>
    implements SingleObserver<T>, Disposable, Runnable {
        private static final long serialVersionUID = 3528003840217436037L;

        final SingleObserver<? super T> downstream;

        final Scheduler scheduler;

        T value;
        Throwable error;

        ObserveOnSingleObserver(SingleObserver<? super T> actual, Scheduler scheduler) {
            this.downstream = actual;
            this.scheduler = scheduler;
        }

        @Override
        public void onSubscribe(Disposable d) {
            if (DisposableHelper.setOnce(this, d)) {
                downstream.onSubscribe(this);
            }
        }

        @Override
        public void onSuccess(T value) {
            this.value = value;
            Disposable d = scheduler.scheduleDirect(this);
            DisposableHelper.replace(this, d);
        }

        @Override
        public void onError(Throwable e) {
            this.error = e;
            Disposable d = scheduler.scheduleDirect(this);
            DisposableHelper.replace(this, d);
        }

        @Override
        public void run() {
            Throwable ex = error;
            if (ex != null) {
                downstream.onError(ex);
            } else {
                downstream.onSuccess(value);
            }
        }
...
    }
复制代码

重写敲黑板,此时逻辑还在observeOn中哦!! ObserveOnSingleObserver接受两个构造参数,actual 下游的观察者 并赋值给downstream 这名字多好啊,下游!scheduler 外部类的scheduler,也就是mainThread,也就是那个HandlerScheduler。 ObserveOnSingleObserver实现了runnable接口,在run方法中调用下游观察者对象 downstream的onError,onSuccess。那下面就找找这个run方法被那个家伙执行的吧。 既然这个内部类接管了上游的回调,由在run方法执行时传递给下游,那在上游回调时肯定得干点什么吧

        @Override
        public void onSuccess(T value) {
            this.value = value;
            Disposable d = scheduler.scheduleDirect(this);
            DisposableHelper.replace(this, d);
        }

        @Override
        public void onError(Throwable e) {
            this.error = e;
            Disposable d = scheduler.scheduleDirect(this);
            DisposableHelper.replace(this, d);
        }
复制代码

直击scheduler.scheduleDirect(this),那也就是HandlerScheduler的scheduleDirect方法,追!

    public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
...
        ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
        Message message = Message.obtain(handler, scheduled);
        if (async) {
            message.setAsynchronous(true);
        }
        handler.sendMessageDelayed(message, unit.toMillis(delay));
        return scheduled;
    }
复制代码

这里代码比较好读了,创建内部ScheduledRunnable对象包装外部的Runnable对象,在run方法中调用外部run方法。使用mainLooper构建的handler发送这条消息。那到目前位置,在示例代码中最后两个方法就分析完了。

结论:在ObserveOn指定的线程决定了紧挨着的订阅者接收线程,内部通过将收到的上游回调参数,用主线程handler切换线程后传递给下游,完成线程切换。也就是ObserveOn影响的是下游的接收线程。

也就是说最后设置的观察者上必须紧紧挨着ObserveOn?就目前分析的结果是这样,但是事实并不是这么简单。

这一个疑问先放一放,接着看map吧

  • 5 map操作符的内部与上下游关系

map方法内部创建SingleMap,也就收一个上游this,还有一个函数对象mapper。很好理解,mapper就是外部创的function嘛,实现了apply方法。

public final class SingleMap<T, R> extends Single<R> {
    final SingleSource<? extends T> source;

    final Function<? super T, ? extends R> mapper;

    public SingleMap(SingleSource<? extends T> source, Function<? super T, ? extends R> mapper) {
        this.source = source;
        this.mapper = mapper;
    }

    @Override
    protected void subscribeActual(final SingleObserver<? super R> t) {
        source.subscribe(new MapSingleObserver<T, R>(t, mapper));
    }
...
复制代码

这里跟前面的差不多,在subscribeActual方法中创建内部观察者订阅给上游,并保存了下游观察者与mapper函数。 重点看一下它的ouSuccess方法

        @Override
        public void onSuccess(T value) {
            R v;
            try {
                v = Objects.requireNonNull(mapper.apply(value), "The mapper function returned a null value.");
...
            t.onSuccess(v);
        }
复制代码

这就很清楚了,接收上游的value,并调用mapper.apply进行转换,再调用下游的观察者的onSuccess传递。这也就是为什么map操作符之后订阅的onSuccess类型需要与apply方法的返回值类型相同了。 除此之外,这里也没有切换线程,也就是说上游回调时在什么线程,那当前就在什么线程。 总结:在此例子中,操作符的执行线程取决于其上游指定的线程。

  • 6 最后来看subscribeOn方法吧

Single.just(1)就没必要记录了,因为他很简单的创建模式,在subscribeActual

中往下游的onSuccess传递1这个值。

subscribeOn内部创建SingleSubscribeOn对象,并接受上游this,与io scheduler 这个调度器。 有过前面的经验这里也直接看subscribeActual

    @Override
    protected void subscribeActual(final SingleObserver<? super T> observer) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<>(observer, source);
        observer.onSubscribe(parent);

        Disposable f = scheduler.scheduleDirect(parent);

        parent.task.replace(f);

    }
    
    
复制代码

哦~又看到了scheduleDirect。不过这里是io调度器的实现了。SubscribeOnObserver也实现了Runnable接口,并在run方法中将自己订阅给上游,又在onSuccess中直接传递给下游。

    static final class SubscribeOnObserver<T>
    extends AtomicReference<Disposable>
    implements SingleObserver<T>, Disposable, Runnable {

        final SingleObserver<? super T> downstream;

        final SequentialDisposable task;

        final SingleSource<? extends T> source;

        SubscribeOnObserver(SingleObserver<? super T> actual, SingleSource<? extends T> source) {
            this.downstream = actual;
            this.source = source;
            this.task = new SequentialDisposable();
        }

        @Override
        public void onSuccess(T value) {
            downstream.onSuccess(value);
        }

        @Override
        public void run() {
            source.subscribe(this);
        }
...省略
    }
复制代码

上游是谁呢?Single.Just 他并没有指定线程,但是订阅他的时候他才开始执行,订阅线程也就意味着他的执行线程,也意味着是下游onSuccess的接收线程。那不就是这里run方法执行的线程嘛。

  • io scheduler 的 scheduleDirect方法

不卖关子了 就是IoScheduler,但是并没有 scheduleDirect方法,那就向上找吧 Scheduler

    @NonNull
    public Disposable scheduleDirect(@NonNull Runnable run) {
        return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
    }
复制代码

恩很简单嘛,继续追!

    @NonNull
    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);

        return task;
    }
复制代码

看最后,w.schedule 执行了任务。不要忘记了这里的createWorker,与schedule都是IoScheduler的方法哦。拐回去看吧

    @NonNull
    @Override
    public Worker createWorker() {
        return new EventLoopWorker(pool.get());
    }
    static final class EventLoopWorker extends Scheduler.Worker {
 ...省略
        private final ThreadWorker threadWorker;

        final AtomicBoolean once = new AtomicBoolean();

        EventLoopWorker(CachedWorkerPool pool) {
            this.pool = pool;
            this.tasks = new CompositeDisposable();
            this.threadWorker = pool.get();
        }
        @NonNull
        @Override
        public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
            if (tasks.isDisposed()) {
                // don't schedule, we are unsubscribed
                return EmptyDisposable.INSTANCE;
            }

            return threadWorker.scheduleActual(action, delayTime, unit, tasks);
        }
    }
复制代码

最终调用到threadWorker.scheduleActual,继续追! 不卖关子直接追到NewThreadWorker

    @NonNull
    public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
...省略
        try {
            if (delayTime <= 0) {
                f = executor.submit((Callable<Object>)sr);
            } else {
                f = executor.schedule((Callable<Object>)sr, delayTime, unit);
            }
...
        return sr;
    }
复制代码

啊executor.submit,executor.schedule熟啊这不是java的线程池api嘛。这里也不用贴代码了,确实是一个核心数为1,非核心线程5-10个的线程池。 到这里也就完成了在后台线程执行上游任务,并且下游默认也是在后台线程接收的逻辑分析。

总结:到此observeOn,与subscribeOn就分析完了,从源码可以看出

  • observeOn是在接收到上游通知后 再切换线程 通知给下游,决定着下游收到通知的线程,如果有多个下游则可以多次切换下游获取通知的线程
  • subscribeOn 是在切换成线程后进行订阅,也就是指定发射线程,也就是指定上游的执行线程,因为是自下儿上的订阅上游,多次使用subscribeOn最终就会切换到到第一次subscribeOn指定的线程,也就是会造成只有第一次设置生效的假象,实际上每一层的线程切换都会执行,只是又浪费又没用。

舒坦~~ 额。。上面还有个问题没搞清楚呢,舒坦什么呀。现在已经1点1刻了。先休息吧,明日再续。

隔日补充 - -!

四、最终订阅的观察者线程到底属于谁调度的线程?

根据上面的理解不难总结: 调用subscribe(Observer)设置的Observer的接收线程在哪里?在离他最近的ObserverOn指定的线程,如果没有呢,就是在第一次指定subscribeOn指定的线程,都没有呢?原始线程。 基于map操作符的测试代码

        Single.just(1)
                .observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread())
                .map(object:Function<Int,Int>{
                    override fun apply(t: Int): Int {
                        println("run2 map 1 线程:${Thread.currentThread().name}")
                        return t+1
                    }
                })
                .map(object:Function<Int,Int>{
                    override fun apply(t: Int): Int {
                        println("run2 map 2 线程:${Thread.currentThread().name}")
                        return t+1
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object:SingleObserver<Int>{
                    override fun onSubscribe(d: Disposable?) {
                        println("run2 onSubscribe 线程:${Thread.currentThread().name}")
                    }
                    override fun onSuccess(t: Int?) {
                        println("run2 onSuccess 线程:${Thread.currentThread().name}")
                    }
                    override fun onError(e: Throwable?) {
                    }
                })
复制代码

本篇仅以最简单的创建类型进行分析,分析明白流式+线程调度的本质。至于其他复杂操作符引申的变化此处不做展开。


END

文章分类
Android
文章标签