RxJava原理浅析

转载请注明出处:http://blog.csdn.net/hjf_huangjinfu/article/details/78421118



概述

        本文内容基于 RxJava 2.1.6 版本,RxAndroid 2.0.1版本,主要是探索一下 RxJava 的内部结构以及其工作流程。



1、看一个简单的例子


        Observable
                .fromArray(1, 2, 3, 4)
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Exception {
                        Log.e("O_O", "filter, Thread : " + Thread.currentThread().getName());
                        return integer % 2 == 0;
                    }
                })
                .observeOn(Schedulers.newThread())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(Integer integer) throws Exception {
                        Log.e("O_O", "map, Thread : " + Thread.currentThread().getName());
                        return integer * 2;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e("O_O", "integer : " + integer + ", Thread : " + Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
看一下输出:
11-02 09:53:38.050 17242-17284/cn.hjf.rxjavatest E/O_O: filter, Thread : RxCachedThreadScheduler-1
11-02 09:53:38.050 17242-17284/cn.hjf.rxjavatest E/O_O: filter, Thread : RxCachedThreadScheduler-1
11-02 09:53:38.050 17242-17284/cn.hjf.rxjavatest E/O_O: filter, Thread : RxCachedThreadScheduler-1
11-02 09:53:38.050 17242-17284/cn.hjf.rxjavatest E/O_O: filter, Thread : RxCachedThreadScheduler-1
11-02 09:53:38.050 17242-17285/cn.hjf.rxjavatest E/O_O: map, Thread : RxNewThreadScheduler-1
11-02 09:53:38.050 17242-17285/cn.hjf.rxjavatest E/O_O: map, Thread : RxNewThreadScheduler-1
11-02 09:53:38.080 17242-17242/cn.hjf.rxjavatest E/O_O: integer : 4, Thread : main
11-02 09:53:38.080 17242-17242/cn.hjf.rxjavatest E/O_O: integer : 8, Thread : main
嗯,没毛病,这段代码的作用就是:
1、在IO线程中,生成 [1,2,3,4] 这几个数字,然后从中选出偶数。
2、在新线程中,对选出来的偶数 [2,4] 进行乘法操作。
3、最后,交给主线程进行打印。


2、RxJava基本结构

上面的代码片段中,涉及到很多对象,下面整理一张类图。







首先分为两大块,第一块就是事件源模块,第二块就是(观察者)监听器模块,这两个模块之间使用 观察者模式来建立联系,
事件源模块,由于RxJava提供了很多操作符来对事件源进行操作,所以使用了 装饰器模式来设计整个事件源模块,事件源分为两大类,一个是原始事件源,直接继承于Observable,一个是事件处理类,继承于AbstractObservableWithUpstream。
Observer以一种 迭代器的形式存在,事件源采用push的方式来输出整个事件流。
观察者模块采用 代理的模式,因为事件流从源头到观察者的中间过程里面,可能会被处理(调度、过滤、转换等等)。



3、对象调用流程

        每一步的对象调用流程,以及关键操作步骤,都在下图中有说明,从操作1到操作12,形成了一个调用链条。链条分为2块,第一块是subscribe链条(1~6),第二块是notify链条(7~12),为什么要区分,因为这个跟线程调度有关系,后面再说。





4、线程切换操作

        RxJava提供了 Scheduler 来提供线程切换机制,主要的调度操作委托给其内部类 Worker 的 schedule 方法,schedule 方法是抽象的,所以每个不同的 Scheduler 都可以有不同的调度实现。
public abstract Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit);
schedule 方法可以把一个 Runnable 提交到其他线程去执行。

        RxJava内部提供了一些具体的 Scheduler 实现,这里先不管每种实现的区别,反正就是把操作调度到其他线程执行,这里主要看一下是怎么调度的。上面提到的两个操作,subscribeOn 和 observeOn ,subscribeOn 主要是影响 subscribe链 和 notify 链,而 observeOn 只能影响 notify 链。

看一下 subscribe 方法:
    public final void subscribe(Observer<? super T> observer) {
        ObjectHelper.requireNonNull(observer, "observer is null");
        try {
            observer = RxJavaPlugins.onSubscribe(this, observer);

            ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");

            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
            Exceptions.throwIfFatal(e);
            // can't call onError because no way to know if a Disposable has been set or not
            // can't call onSubscribe because the call might have set a Subscription already
            RxJavaPlugins.onError(e);

            NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
            npe.initCause(e);
            throw npe;
        }
    }
主要是调用了 subscribeActual 方法,它是抽象方法,具体的事件源去实现自己的订阅策略
    protected abstract void subscribeActual(Observer<? super T> observer);

ObservableSubscribeOn

看一下 ObservableSubscribeOn 的 subscribeActual 方法:
    public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
        s.onSubscribe(parent);
        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }
重点关注一下这一句代码
scheduler.scheduleDirect(new SubscribeTask(parent))
SubscribeTask是什么?是一个Runnable
final class SubscribeTask implements Runnable
再看一下 SubscribeTask 里面做了什么
        @Override
        public void run() {
            source.subscribe(parent);
        }
所以大概意思就是,Scheduler 把 subscribe 操作,切换到 Scheduler 内部的运行线程,所以它可以影响 subscribe 链。


ObservableObserveOn

再看一下 ObservableObserveOn 的 subscribeActual 方法,
    @Override
    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));
        }
    }
我们不关注 if 里面的内容,它不执行线程切换,只是把操作放到后面执行,关注这段代码:
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
在之前运行的线程中执行 subscribe 调用,再看一下 ObserveOnObserver ,它是一个 Runnable
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T> implements Observer<T>, Runnable
在 onNext 中,调用了 Scheduler.Worker 的 schedule 方法,成功的把 notify 操作 切换到其他线程了。
        @Override
        public void onNext(T t) {
            if (done) {
                return;
            }

            if (sourceMode != QueueDisposable.ASYNC) {
                queue.offer(t);
            }
            schedule();
        }
        void schedule() {
            if (getAndIncrement() == 0) {
                worker.schedule(this);
            }
        }
所以它只能影响 notify 链,而不能影响 subscribe 链。


5、事件过滤转换操作

简述一下事件过滤转换操作过程,这里只用 filter 来举例子。RxJava 所谓的操作符,只不过是生成不同的事件源对象(ObservableSource 子类的实例),事件源分为几大类:
原始事件流
单一事件流 :一个单一的事件源
组合事件流 :由多个单一或者组合事件源组合而成的组合事件流(merge等等)
装饰器流
转换流 :对事件进行加工处理后的事件流(filter等等)
调度流 :对事件执行线程的调度(subscribeOn等等)

这里看一下 filter 操作生成的事件流, 对应的对象是 ObservableFilter ,看一下 subscribeActual 方法:
    @Override
    public void subscribeActual(Observer<? super T> s) {
        source.subscribe(new FilterObserver<T>(s, predicate));
    }
subscribe 操作委托给内部的事件源去操作,然后用一个 FilterObserver 来包装原始的 Observer,看一下 FilterObserver 主要代码:
        @Override
        public void onNext(T t) {
            if (sourceMode == NONE) {
                boolean b;
                try {
                    b = filter.test(t);
                } catch (Throwable e) {
                    fail(e);
                    return;
                }
                if (b) {
                    actual.onNext(t);
                }
            } else {
                actual.onNext(null);
            }
        }
内部基于一个 Predicate 对象来执行真正的过滤操作,如果满足过滤条件,该事件就继续向下分发,如果不符合,就被过滤掉,典型的代理模式。






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值