从源码剖析RxJava基本工作原理(1)

45 篇文章 0 订阅
8 篇文章 0 订阅

什么是Rxjava

ReactiveX是一个通过使用可观察序列来编写异步和基于事件的程序的库。
它扩展了观察者模式以支持数据和/或事件序列,并增加了运算符,使您可以声明性地组合序列,同时抽象出对低级线程,同步,线程安全性,并发数据结构和非线程等事物的关注阻塞I / O

1.简单实例

以上文字的描述很精炼的说出了rxJava是干啥的,以及它的优点,下面我会从简单的使用案例中去剖析rxJava的工作原理。

Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onComplete();
            }
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e(TAG, "debounce:onSubscribe == 订阅");
            }
            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "debounce:onNext ==" + integer);
            }
            @Override
            public void onComplete() {
                Log.e(TAG, "debounce:onComplete == ");
            }
            @Override
            public void onError(Throwable e) {}
        });

我们如果使用过rxJava的话,肯定知道当调用了subscribe之后,那么事件就开始发射,观察者就开始消费事件了。那么我们就从subscribe()这个函数开始剖析源码。

    @SchedulerSupport(SchedulerSupport.NONE)
    @Override
    public final void subscribe(Observer<? super T> observer) {
        ObjectHelper.requireNonNull(observer, "observer is null");
        try {
      		...//省略
            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
            ....//省略
            throw npe;
        }
    }

可以看到当我们调用了subscribe函数之后,就会调用subscribeActual方法,我们进去看看:
在这里插入图片描述
是个observable类的抽象方法,有很多实现,咱们的操作符和create创建出来的observable都实现了这个方法。咱们还是先看下我画好的类图:
在这里插入图片描述
这里就知道了,结合一开头提供的代码知道subscribeActual()函数调用了ObservableCreate的实现方法。再来看下create源码,做了什么:

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

创建一个ObservableCreate返回,参数是ObservableOnSubscribe对象,在进去看看ObservableCreate的实现是怎么实现的。

public final class ObservableCreate<T> extends Observable<T> {
    final ObservableOnSubscribe<T> source;
    public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }
    @Override
    protected void subscribeActual(Observer<? super T> observer) {
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        observer.onSubscribe(parent);
        ...
     	source.subscribe(parent);
     	...
    }

subscribeActual()函数的流程就是,接受到观察者参数之后,将其封装成emitter对象,然后首先调用观察者的onSubscribe函数,在调用source的subscribe()函数。我们从这个实现类的构造函数可以知道source就是我们create方法传入的ObservableOnSubscribe实现类,到这里也就明白了,文章一开头的那段代码,为啥观察者的函数调用顺序是这样的:

19:43:31.725 18200/cn.com.egova.test E/MainActivity: ui当前线程:2
19:43:31.727 18200/cn.com.egova.test E/MainActivity: debounce:onSubscribe == 订阅
19:43:31.727 18200/cn.com.egova.test E/MainActivity: debounce:onNext ==1
19:43:31.727 18200/cn.com.egova.test E/MainActivity: debounce:onComplete == 

当然我们也明白了observer.onSubscribe(parent);这句话其实和Observable.subscribe()这句话是处于同一个线程的,调用链上没有线程的切换,理所应当是同一个线程。

2.操作符系列

2.1 map操作符

map操作符可以说是rxJava中最好理解的一个操作符了,先从这个入手开始剖析操作符的原理。
我们在开头那段代码中加入map操作符之后,如下:
在这里插入图片描述
简单展示,所以实现较为简单,重要还是看原理,我们点击进去看下如何实现的
在这里插入图片描述
看到ObservableMap,根据类图我们知道,它还是继承着observable类,而里面的source参数是ObservableSource(也就是我们map操作符上面的create创建出来的observable对象,它继承自ObservableSource),在点击进去看下实现:

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
    final Function<? super T, ? extends U> function;

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

    @Override
    public void subscribeActual(Observer<? super U> t) {
        source.subscribe(new MapObserver<T, U>(t, function));
    }

还是熟悉的味道,熟悉的配方,我们看到subscribeActual的实现是,调用source.subscribe()的方法参数封装下游的观察者MapObserver对象,按照流程我们知道source就是observable对象,subscribe方法最后调用的就是observableCreate的subscribeActual方法,这样的话也就形成。

observableCreate类内							  |ObservableMap类内		     |Observer类内
observer.onSubscribe(parent);					  | --> ObservableMap.onSubscribe| Observer.onSubscribe  
							/emitter.onNext(1);   | --> ObservableMap.onNext	 | --> Observer.onNext
source.subscribe(parent)-->| 					  |                              |
							\emitter.onComplete();| --> ObservableMap.onComplete | --> Observer.onComplete 
                				 

其实的话observableMap的onNext函数不需要去细看不影响流程,但是的话,对于理解代理模式的话还是有好处的,源码如下:

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 {
                v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
            } catch (Throwable ex) {
            	...
            }
            downstream.onNext(v);
        }

其实就是把参数传递过来的T类型对象,用mapper转换下生成U类型对象,继续调用下游的onNext方法把U类型对象传递下去。

可以根据最开头的代码,梳理一下整个过程的流程图,如下:
在这里插入图片描述

结合上面的整个代码做个总结,就是我们从create函数开始创建了事件源之后,后面再接着的操作符就是事件订阅过程,操作符将返回一个observable对象,内部成员持有上游的观察者作为source,subscribe函数一旦触发,那么就会封装下游的观察者生成一个observer代理类,用于将上游onNext函数传递过来的事件源对象接受过来,然后调用操作符的操作之后转化成新的对象,再将对象传递给下游的observer代理类,也就是调用一下下游的onNext函数。map操作符是个转化操作,还要其他的好多操作符,比如切换线程,过滤器,flatMap等等操作符,以此类推都可以推导出来rxJava的操作符的一些原理东西。

那么就可以知道操作符map等等调用完成之后,是创建了新的observable被观察者对象(代理了上游),subscribe函数调用之后,是将下游的observer观察者对象包装起来(代理下游),作为参数传递给上游source对象作为subscribe方法的参数。这样那么就可以知道,操作符规定事件流转的方向,并且规定了事件流转过程中具体转换细节,订阅操作只是触发了这一过程。

上面我只用了一个map,想象一下,如果中间加了很多操作符,流程其实也是一样的,只是再上面的我所画的图中间再多加几个泳道而已。

我们再来看下createEmitter类,代码如下:

static final class CreateEmitter<T>
    extends AtomicReference<Disposable>
    implements ObservableEmitter<T>, Disposable {
        final Observer<? super T> observer;
        CreateEmitter(Observer<? super T> observer) {
            this.observer = observer;
        }
        @Override
        public void onNext(T t) {
            if (t == null) {
                onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
                return;
            }
            //注意这句话
            if (!isDisposed()) {
                observer.onNext(t);
            }
        }

其实我们还可以推导出来observer.onSubscribe(Disposable d)函数中的参数Disposable,就是ObservableCreate类内的静态内部类CreateEmitter,我们通常使用Disposable来管理我们的rxJava的生命周期,由此可以推断,Disposable如果调用了销毁的方法,只是将状态设置为销毁状态,isDisposed()返回为false,这样下游就收不到onNext下发的事件。

题外话题disposable

一般的操作符的disposable接口的默认实现是调用上游的dispose()方法,也就是从下游一直回溯到上游,依次调用dispose()方法,那么我们可以推测dispose()方法可以阻断未到达的操作符,比如:在事件发射函数中做了长时间网络请求,在这期间我们调用了disposable.dispose()方法的话,最终回溯到createEmitter的dispose()方法,createEmitter的这个方法是个空方法,因此不会影响方法的执行,但是下游全是DISPOSED状态,所以下游事件不会去接受和消耗,从Emitter已经截断了,比如下面这个代码:

 Log.e(TAG,"主线程ID:"+Thread.currentThread().getId());
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.e(TAG,"subscribe线程ID:"+Thread.currentThread().getId());
                emitter.onNext(1);
                emitter.onComplete();
                Log.e(TAG,"subscribe方法执行完毕");
            }
        })
//        .subscribeOn(Schedulers.io())
        .map(new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) throws Exception {
                Log.e(TAG,"map操作符线程ID:"+Thread.currentThread().getId());

                return integer;
            }
        })
//        .observeOn(Schedulers.io())
        .subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                d.dispose();
                Log.e(TAG,"onSubscribe线程ID:"+Thread.currentThread().getId());
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG,"onNext线程ID:"+Thread.currentThread().getId());
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "debounce:onError == " + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete线程ID:"+Thread.currentThread().getId());
            }
        });

只要onSubscribe一调用就dispose方法,看看打印的什么:

10:12:40.398 17802-17802/cn.com.egova.test E/MainActivity: 主线程ID:2
10:12:40.418 17802-17802/cn.com.egova.test E/MainActivity: onSubscribe线程ID:2
10:12:40.418 17802-17802/cn.com.egova.test E/MainActivity: subscribe线程ID:2
10:12:40.418 17802-17802/cn.com.egova.test E/MainActivity: subscribe方法执行完毕

假如我们将onSubscribeOn操作符加上去,来看subcribeOn操作的具体实现:

@Override
public void subscribeActual(final Observer<? super T> observer) {
    final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
    observer.onSubscribe(parent);
    parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable>
    		implements Observer<T>, Disposable {
      @Override
      public void dispose() {
          DisposableHelper.dispose(upstream);
          DisposableHelper.dispose(this);
      }

那么知道,回溯到这个操作符的时候,调用的就是上游的方法和schedule的dispose方法。这里具体是啥我们不去追究,基本意思就是将这个schedule调度器的线程给暂停掉。这样的话,Emitter如果是个耗时操作的话,在耗时操作完成之前dispose掉,那么这个线程就会被停掉,那么耗时操作就会被打断。
代码如下:


        Log.e(TAG,"主线程ID:"+Thread.currentThread().getId());
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.e(TAG,"subscribe线程ID:"+Thread.currentThread().getId());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Log.e(TAG,"subscribe打断异常");
                }
                emitter.onNext(1);
                emitter.onComplete();
                Log.e(TAG,"subscribe方法执行完毕");
            }
        })
        .subscribeOn(Schedulers.io())
        .map(new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) throws Exception {
                Log.e(TAG,"map操作符线程ID:"+Thread.currentThread().getId());

                return integer;
            }
        })
//        .observeOn(Schedulers.io())
        .subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                d.dispose();
                Log.e(TAG,"onSubscribe线程ID:"+Thread.currentThread().getId());
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG,"onNext线程ID:"+Thread.currentThread().getId());
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "debounce:onError == " + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete线程ID:"+Thread.currentThread().getId());
            }
        });

打印的结果如下:

10:26:42.595 19515-19515/cn.com.egova.test E/MainActivity: 主线程ID:2
10:26:42.664 19515-19515/cn.com.egova.test E/MainActivity: onSubscribe线程ID:2

我们发现直接就没有机会执行Emitter的方法了,假设我们的d.dispose()方法延迟0.5秒执行的话,

    new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                dp.dispose();
            }
        }).start();

结果打印的是:

10:30:20.794 19978-19978/cn.com.egova.test E/MainActivity: 主线程ID:2
10:30:20.864 19978-19978/cn.com.egova.test E/MainActivity: onSubscribe线程ID:2
10:30:20.870 19978-20026/cn.com.egova.test E/MainActivity: subscribe线程ID:763
10:30:21.385 19978-20026/cn.com.egova.test E/MainActivity: subscribe打断异常
10:30:21.385 19978-20026/cn.com.egova.test E/MainActivity: subscribe方法执行完毕

结果也符合预期。
取消订阅的链式结构如下:
在这里插入图片描述

基本的原理性已经剖析完了,下一篇文章我将剖析一下线程切换的问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值