Rxjava源码解析

前言

Rxjava可能是现在最流行的异步请求框架了。经常可以听到各种关于他的话题,具体有多好用我原来还真不知道,因为公司里面根本不用!!!。用到异步的时候直接自己手撸一个线程池就好了,如果涉及到切换线程的时候比如到主线程,直接handler。用习惯了还是有点小骄傲的,唯手顺耳。哎,还是too yanger too simple啊。直到详细了解了Rxjava,并自己敲了几个demo后,才知道tmd之前自己是多么的。。。。最重要的是,听说现在面试官都喜欢问这个可怜,那没办法了,得好好的分析下了。


看之前注意一下三点:

1.本文前半部分源码分析是基于:

compile 'io.reactivex:rxjava:1.0.14'

2.贴出来分析的是rxjava执行的主要过程,代码都是抽取的主要代码,有些是伪代码。

3.本文分析中,旧的被观察者一般指当前生成的新的被观察者的上层被观察者。旧的观察者指的是当前生成的新的观察者的下层观察者。


几个概念

分析源码有几个对象得想搞清楚,不然,那几个对象自己读着读着就把自己绕晕了。文中有的地方直接使用中文了,英文自己绕的也晕。

观察者:Observer Subscriber    

被观察者:Observable

订阅关系:subscribe

扫描二维码关注公众号,回复: 1065472 查看本文章


源码分析

分析源码的时候我喜欢根据使用方式去一步一步的分析。一个简单的Rxjava实现:

        //被观察者对象
        Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subservber<Integer> subservber) {
            }
        });
        //观察者对象
        Subservber<Integer> subservber = new Subservber<Integer>() {
            @Override
            public void onNext(Integer integer) {
            }
            @Override
            public void onError(Throwable t) {
            }
            @Override
            public void onCompleted() {
            }
        };
        //被观察者订阅观察者
        observable.subscribe(subservber);

创建被观察者对象和观察者对象然后 使用被观察者对象订阅观察者对象。

首先创建被观察者对象我们需要知道被观察者对象在这个例子里面用到的有啥,一个OnSubscribe 对象,掉了自己的create方法创建的,带着这些问题源码里面找下,去掉无用的代码后:

public class Observable<T> {
    final OnSubscribe<T> onSubscribe;  
    protected Observable(OnSubscribe<T> f) {
        this.onSubscribe = f;
    }
    public final static <T> Observable<T> create(OnSubscribe<T> f) {
        return new Observable<T>(f);
    }
    public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {
        // cover for generics insanity
    }}
public interface Action1<T> extends Action {
    void call(T t);
}

        可以发现,OnSubscribe是被观察者对象Observable内部的一个接口,这个接口继承自Action1。这个接口里面有一个call方法,有点熟悉哦,就是我们实例化后传入内部类里面的call方法。被观察者对象内部会持有一个OnSubscribe对象的引用,这个对象是在被观察者对象创建的时候传入的。也就是说,一个被观察者对象就和一个OnSubscribe对应。OnSubscribe的call方法参数也比较特殊,是一个Subscriber对象,泛型 T 对应的是Subscribe<? super T>。

    接下来是观察者对象的创建,首先了解下观察者对象。Rxjava有俩个,一开始的时候我们就说过,一个是Observer,另一个是Subscriber,他们有啥区别了?先贴下相关代码:

public interface Observer<T> {
    void onCompleted();
    void onError(Throwable e);
    void onNext(T t);
}
public abstract class Subscriber<T> implements Observer<T> {
    public void onStart() {
        // do nothing by default
    }
 }

可以发现,Observer是一个接口,里面只有三个方法。而Subscriber是一个抽象类,实现了Observer,并添加了个onStart方法。

接下来就是订阅方法了,执行了这个方法后,整个系统就开始执行,这像是一个钥匙一般。还是先贴出相关代码:

    public final Subscription subscribe(final Observer<? super T> observer) {
        if (observer instanceof Subscriber) {
            return subscribe((Subscriber<? super T>)observer);
        }
        return subscribe(new Subscriber<T>() {
            @Override
            public void onCompleted() {
                observer.onCompleted();
            }
            @Override
            public void onError(Throwable e) {
                observer.onError(e);
            }
            @Override
            public void onNext(T t) {
                observer.onNext(t);
            }
        });
    }

subscribe会先判断是否为Subscriber对象,如果是就直接调用重载方法,如果不是会新建一个Subscriber然后在这个Subsciber对象对应的回调方法里面调用自己的,将触发的事件传递下去。而重载的subscribe最终走到了这里:

 private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
        // new Subscriber so onStart it
        subscriber.onStart();
        onSubscribe.call(subscriber);
  } 

上文说过一个Observable对象内部有一个OnSubscribe,这样Observable通过onSubscribe将他和Subscriber联系起来,也就是将被观察者和观察者进行了绑定。我们在call方法里面调用onNext这些方法的时候,实际上是调用的是观察者对象Subscriber的方法。可以看到这个方法里面会先执行subscriber的onStart方法。也就是说,在哪个线程执行的subscribe,这个onStart方法就会在哪个`线程执行。然后使用onSubscribe执行call方法,参数传观察者对象。call的方法执行,整个系统就运行开始,我们在call方法里面设置的观察者的回调也会开始执行。其实OnSubscribe(被观察者)的call方法里面的Subscriber(观察者)就是方法subscribe(订阅)里面的Subscriber(观察者),这点对后面的内容很重要,一定要记得。


操作符map

Rxjava一个强大的地方就是支持map操作,就是可以将一个对象变为另一个对象。首先看下map需要的参数Func1的源码:

public interface Func1<T, R> extends Function {
    R call(T t);
}

Func1里面只有一个call方法。这个call方法的作用是将 T 类型 转换成 R 类型。也就是map的作用,将一个对象变为另一个对象。具体怎么做了?跟着源码向下走:

 public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
        return lift(new OperatorMap<T, R>(func));
    }

map方法里面会执行一个lift方法,参数为OperatorMap。而这个OperatorMap实例化的时候需要func1作为参数,这个就是转换的关键,我们后边再详说这个。然后lift方法先不看,这个OperatorMap是个啥了?

public final class OperatorMap<T, R> implements Operator<R, T> {
    private final Func1<? super T, ? extends R> transformer;
    public OperatorMap(Func1<? super T, ? extends R> transformer) {
        this.transformer = transformer;
    }
    @Override
    public Subscriber<? super T> call(final Subscriber<? super R> o) {
        return new Subscriber<T>(o) {
            @Override
            public void onCompleted() {
                o.onCompleted();
            }
            @Override
            public void onError(Throwable e) {
                o.onError(e);
            }
            @Override
            public void onNext(T t) {
                o.onNext(transformer.call(t));
      }};}}

 public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {
        // cover for generics insanity
    }

可以看到,OperatorMap 实现了Operator。Operator继承自Func1,只不过Func1的俩个参数是俩个观察者Subscriber对象。也就是说,他也有call方法,只不过call方法会将一个Subscriber作为参数,然后返回值为另一个Subscriber对象。回到OperatorMap的call方法里面,我们看到他新建了一个观察者对象,然后在对应的回调方法里面调用了方法参数里面的观察者对象o的对应的回调,做到了一个回调的传递。也就是新的观察者对象会将对应的事件传递回o这个旧的观察者对象里面去。重点看下回调的onNext方法,这个方法在调用o的onNext的时候回西安调用transformer,这个对象是创建OperatorMap的时候传入的Func1,然后通过他的call做的转换。我们在使用map的时候要在Func1的call方法里面自己实现转换的过程。这个也是Rxjava的优点,将变化用接口隔离。

然后我们看下lift方法的实现:

    public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
        return new Observable<R>(new OnSubscribe<R>() {
            @Override
            public void call(Subscriber<? super R> oldSubscriber) {
                    Subscriber<? super T> newSubscriber= operator.call(oldSubscriber);
                    newSubscriber.onStart();
                    onSubscribe.call(newSubscriber);}}});}

lift方法会先返回一个新建的被观察者Observable对象,然后在其call方法里面使用opertor的call方法,参数为观察者对象oldSubscriber,返回值为一个观察者对象newSubscriber。在上面的分析的时候我们看到:

lift(new OperatorMap<T, R>(func))

所以,这个Operator具体实例化的是OperatorMap对象。刚刚我们分析了,OperatorMap对象的call方法会新建一个观察者Subscriber对象返回,并在新的观察者对象的事件传递回旧的观察者对象。然后new调用他的onStart方法,然后使用lift方法所在的被观察者对象Observable的onSubscribe去调用call,参数为newSubscriber


        好了整个过程分析完了,我们将这个完整的流程串一下。map会新生成一个被观察者对象和一个观察者对象,然后新的被观察者对线订阅旧的观察者对象(subscribe方法),旧的被观察者对象订阅新的观察者对象(onSubscribe.call(newSubscriber))。也就是新的被观察者会执行call,然后参数是旧的观察者(subscribe方法)。在新的被观察者的call方法里面调用旧观察者的onSubscribe.call,实现了从底层往上传递call的调用。然后在旧观察者call方法里,新观察者对象(new)的对应回调里面调用旧的观察者对象(old)的回调,向下去传递回调方法。在onNext在传递的时候要通过Func1的call转换下类型。其本质是在旧的被观察者和旧的观察者之间接入了个新的被观察者和新的观察者来做的转换。

如果为了理解这个过程我们可以简化为如下代码:

    public <R> Observable<R> map(final Func<T, R> func) {
        return create(new OnSubscribe<R>() {  //返回了新的被观察者去订阅旧的观察者(他去执行subscribe方法)
            @Override
            public void call(final Subservber<R> old) {//旧的观察者对象
                //onSubscribe代表着旧的被观察者
                onSubscribe.call(new Subservber<T>() { //我们new了新的观察者出来
                    @Override
                    public void onNext(T t) {
                        old.onNext(func.call(t));  //在传递回调的同时通过func的call进行转换
                    }
                    @Override
                    public void onError(Throwable t) {
                        old.onError(t);   //新的观察者会调用旧的观察者对象的方法
                    }
                    @Override
                    public void onCompleted() {
                        old.onCompleted();
                    }
                });}); }

线程调度

这部分源码使用的是:

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
因为1.0的源码看晕了 T.T

        rxjava线程调度也是非常强大的功能。我们可以指定Observable执行的线程和Subscribe执行的线程。在一些场景下非常有用。比如我们经常做的,异步加载数据,然后去显示在控件里面,加载是在子线程里面做的,显示是ui线程。原来我们的实现一般都是AsyncTask + handler结合使用。在Rxjava里面直接指定俩个调度器就行了,但是rxjava内部是怎么去做的呢?我们先看Scheduler然后在看subscribeOn 和observeOn。

Scheduler
public abstract class Scheduler {
    public abstract Worker createWorker();
    public abstract static class Worker implements Subscription {  //真正做事的是Worker
        public abstract Subscription schedule(Action0 action);  //主要的执行方法
        public abstract Subscription schedule(final Action0 action, final long delayTime, final TimeUnit unit);
   }}

        scheduler是一个抽象方法,里面有个内部类Worker。其实线程调度是由这个Worker方法完成的,这个类有schedule方法,这个是调度器执行的方法,他的参数有Action0,这个类有个方法call。我们具体的看一个scheduler实现类:

NewThreadScheduler 

public final class NewThreadScheduler extends Scheduler {
    private final ThreadFactory threadFactory;

    public NewThreadScheduler(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }
    @Override
    public Worker createWorker() {
        return new NewThreadWorker(threadFactory);  //创建newThreadWorker
    }
}

        我们发现他主要是新建了一个NewThreadWorke,哪newThreadWorke是什么呢?

public class NewThreadWorker extends Scheduler.Worker implements Subscription {
    private final ScheduledExecutorService executor;
    /* package */
    public NewThreadWorker(ThreadFactory threadFactory) {
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, threadFactory);  //新建一个线程池
        executor = exec;
    }
    @Override
    public Subscription schedule(final Action0 action) {
        return schedule(action, 0, null);
    }
    @Override
    public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) {
        return scheduleActual(action, delayTime, unit);
    }
    public ScheduledAction scheduleActual(final Action0 action, long delayTime, TimeUnit unit) {
        Action0 decoratedAction = schedulersHook.onSchedule(action);  //直接返回了action0
        ScheduledAction run = new ScheduledAction(decoratedAction);  //传入了action 返回了一个runnable的实现类
        Future<?> f;
        if (delayTime <= 0) {
            f = executor.submit(run);   //让线程池执行这个runnable
        } else {
            f = executor.schedule(run, delayTime, unit);  //有延时的时候执行这个
        }
        run.add(f);
        return run;
    }
}

        在NewThreadWorker的构造函数里面创建了一个线程池对象。他的schedule方法最后都是执行的scheduleActual方法。这个方法里面会使用Action0对象,Action0类只有一个call方法。然后,使用这个这个action0对象生成一个ScheduledAction对象,这个对象实现了Runnable。然后在使用早已创建好的线程池对象executor去执行他。我们来看看ScheduledAction对象内部做了什么吧。

public final class ScheduledAction extends AtomicReference<Thread> implements Runnable, Subscription {
    final Action0 action;
    public ScheduledAction(Action0 action) {
        this.action = action;
    }
    @Override
    public void run() {
        action.call();  //run方法里面执行了actioin的call方法
    }
}

        我们可以看到,他是Runnable的子类,然后在自己的run方法里面会执行action的call,所以action对象的call是运行在设置的线程里面的


        我们把整个newThreadScheduler的逻辑顺一遍。newThreadScheduler类里面主要是新建了一个NewThreadWorker去干活。NewThreadWorker里面有一个线程池对象,然后他的scheduleActual方法里面会将一个action0对象的call方法放到线程池里执行。

subscribeOn

        开始subscribeOn的源码分析。首先看下这个方法里面做了什么:

public final Observable<T> subscribeOn(Scheduler scheduler) {
        return create(new OperatorSubscribeOn<T>(this, scheduler));
}

        新建了一个Observable对象,使用的参数是一个OperatorSubscribeOn对象,这个对象应该是OnSubscribe的子类。创建的时候会将当前的被观察者对象Observable和设置的调度器传进去。我们来看下OperatorSubscribeOn的源码:


public final class OperatorSubscribeOn<T> implements Observable.OnSubscribe<T> {
    final Scheduler scheduler;  //调度器对象
    final Observable<T> source;  //原被观察者对象
    public OperatorSubscribeOn(Observable<T> source, Scheduler scheduler) {
        this.scheduler = scheduler;
        this.source = source;
    }
    @Override
    public void call(final Subscriber<? super T> subscriber) {
        final Scheduler.Worker inner = scheduler.createWorker();  //拿到调度器干活的Worker对象
        inner.schedule(new Action0() {   //调用worker的schedule方法,方法是action0
            @Override
            public void call() {        //这个方法运行在我们设置的调度器的线程中,详情看NewThreadWorker分析。
                Subscriber<T> s = new Subscriber<T>(subscriber) {
                    @Override
                    public void onNext(T t) {
                        subscriber.onNext(t);   //回调的传递
                    }
                    @Override
                    public void onError(Throwable e) {
                        subscriber.onError(e);
                    }
                    @Override
                    public void onCompleted() {
                        subscriber.onCompleted();
                    }
                };
                source.unsafeSubscribe(s);  //原被观察者对象订阅了新的观察者对象
            }});}}

        这个类继承自OnSubscribe,所以他有call方法,并且call方法的Subscriber是他下级的Subscriber。这个类里面有俩个属性,一个是当前被观察者对象,另一个是设置的调度器对象。主要来看下call方法的实现。首先,拿到调度器的worker,然后执行worker的schedule方法,并新建一个action0的对象。通过上面分析NewThreadWorker我们知道了,这个方法的作用就是将action0的call方法放到调度器的线程中去执行。哪action0的call方法里面有啥了?接着往下看,call方法里面会新建一个Subscriber对象,在之前的subscribeOn方法里面新建了一个Observable,记住这俩个对象。接着看,发现新建的观察者对象对应的回调方法里面都会调用参数里面的观察者,也就是旧的观察者对应的回调,这就是一个事件的传递。接下来,原被观察者对象source会订阅新观察者对象。

        这块儿涉及到了4个对象,新的被观察者对象,新的观察者对象,原观察者对象,原(旧)观察者对象(就是OnSubscribe的call方法的参数,他是由接下来的代码可能是subscribe方法产生的)。他们的关系是,原观察者对象被新的被观察者对象订阅(比如接下来调用了subscribe),新的观察者对象的call方法被执行,在这里,原被观察者对象订阅了新的观察者对象。注意这部分的执行在调度器的线程里面,之后的调用都在调度器的线程里面执行了,然后原被观察者对象的call方法执行,在里面调用新观察者对应的回调,比如onNext。然后新观察者的onNext回调会调用原观察者对应的onNext,完成回调过程,下图就是上述过程。


自己写的简化后的代码:

   public Observable<T> subscribeOn(final Scheduler scheduler){
        return create(new onSubscribe<T>() {   //创建新的被观察者对象
            @Override
            public void call(final Subscriber<T> subscriber) {
                Scheduler.Worker worker = scheduler.createWorker();  //拿到调度器的worker
                worker.schedule(new Runnable() {                      //worker执行schedule方法,这里我们直接放runnable,让线程池去执行
                    @Override
                    public void run() {
                        Subscriber<T> s = new Subscriber<T>(){        //新的观察者对象
                            @Override
                            public void onNext(T t) {
                                subscriber.onNext(t);                   //新旧观察者传递事件
                            }
                            @Override
                            public void onError(Throwable t) {
                                subscriber.onError(t);
                            }
                            @Override
                            public void onCompleted() {
                                subscriber.onCompleted();
                            }
                        };
                        onSubscribe.call(s);                            //在新的被观察者对象call里调用原被观察者对象call,完成call调用。并且调用过程再线程里面执行
                    }
                });
            }
        });
    }

observeOn

observeOn的源码比较复杂,在我们设置了observeOn后会走到这里:

   public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        return lift(new OperatorObserveOn<T>(scheduler, delayError, bufferSize));
    }

        发现其最终是借助lift方法实现的。在上面我们已经分析了lift方法,其本质就是生成了一个新的被观察者和旧的观察者对象,然后和旧的被观察者和新的观察者相互订阅。并且lift方法的参数是一个Operator对象,他有call方法,这个方法会接收旧的观察者对象生成新观察者对象,并传递对应的回调事件。

了解了lift后,接下来看看OperatorObserveOn的实现:

public final class OperatorObserveOn<T> implements Operator<T, T> {

    private final Scheduler scheduler;
    private final boolean delayError;
    private final int bufferSize;

    public OperatorObserveOn(Scheduler scheduler, boolean delayError) {
        this(scheduler, delayError, RxRingBuffer.SIZE);
    }
    public OperatorObserveOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        this.scheduler = scheduler;
        this.delayError = delayError;
        this.bufferSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE;
    }

    @Override
    public Subscriber<? super T> call(Subscriber<? super T> child) {
        ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize);  //生成新的Subscriber对象,参数里面包含就的Subscriber对象child
        return parent;
    }

    /** Observe through individual queue per observer. */
    private static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 {      //继承Subscriber 并实现了Action0
        final Subscriber<? super T> child;
        final Scheduler.Worker recursiveScheduler;
        public ObserveOnSubscriber(Scheduler scheduler, Subscriber<? super T> child, boolean delayError, int bufferSize) {
            this.child = child;
            this.recursiveScheduler = scheduler.createWorker();   //直接返回调度器的worker对象
        }

        @Override
        public void onNext(final T t) {
            schedule();                 //回调方法都会执行这个方法schedule
        }

        @Override
        public void onCompleted() {
            schedule();
        }

        @Override
        public void onError(final Throwable e) {
            schedule();
        }

        protected void schedule() {
            recursiveScheduler.schedule(this);     //使用worker执行schedule,那么,对应的call就运行在了指定调度器的线程中。
        }
        // only execute this from schedule()
        @Override
        public void call() {
            //这里面的代码都是运行在指定线程中的
            final Subscriber<? super T> localChild = this.child;   //旧的观察者对象
            for (;;) {
                while (requestAmount != currentEmission) {
                    if (checkTerminated(done, empty, localChild, q)) {
                        return;
                    }
                    localChild.onNext(localOn.getValue(v));  //这里调用了旧的观察者对象的回调方法,就相当于新的观察者对象对应的回调里面会调用旧的观察者的回调
                }
            }
        }

        boolean checkTerminated(boolean done, boolean isEmpty, Subscriber<? super T> a, Queue<Object> q) {
            if (done) {
                if (delayError) {
                    Throwable e = error;
                    if (e != null) {
                        a.onError(e);       //这里调用了旧的观察者对象的回调方法,就相当于新的观察者对象对应的回调里面会调用旧的观察者的回调
                    } else {
                        a.onCompleted();
                    }
                } else {
                    a.onCompleted();
                    return true;
                }
            }
            return false;
        }}}

        可以看到,OperatorObserveOn实现了Operator,所以他有一个call方法,并且会返回新的观察者对象。这个新观察者对象是还实现了action0,所以他也有一个call方法。新观察者并且对应的回调方法都执行了一个方法schedule。这个方法会使用调度器的worker执行schedule,参数是将当前类(实现了action0)。所以当前类的call执行了调度器的线程中,这个方法里面会按照不同的情况(具体实现不去分析)去调用旧的观察者对应的回调。因为执行的发起是在新的观察者的回调中,最终执行的是旧的观察者的回调。所以,做到了将事件传递到新线程中旧的观察者的回调方法里,完成线程的切换。

        这块儿还有一个注意的,切换的线程里面跑的是回调的传递,而call的传递是在lift方法所在的线程中。

自己简化后的代码:

    public Observable<T> observeOn(final Scheduler scheduler){
        return create(new onSubscribe<T>() {
            @Override
            public void call(final Subscriber<T> subscriber) {                                     //新的观察者对象
                final Scheduler.Worker worker = scheduler.createWorker();  //拿到调度器的worker
                onSubscribe.call(new Subscriber<T>() {                      //旧的被观察者对象call新的观察者对象,这个时候还在当前线程中
                    @Override
                    public void onNext(final T o) {
                        worker.schedule(new Runnable() {
                            @Override
                            public void run() {                             //当有事件传递过来的时候,就切换到worker去调用旧的观察者的回调,完成线程切换。但是仅限于回调的传递
                                subscriber.onNext(o);           
                            }
                        });
                    }

                    @Override
                    public void onError(final Throwable t) {
                        worker.schedule(new Runnable() {
                            @Override
                            public void run() {
                                subscriber.onError(t);
                            }
                        });
                    }

                    @Override
                    public void onCompleted() {
                        worker.schedule(new Runnable() {
                            @Override
                            public void run() {
                                subscriber.onCompleted();
                            }
                        });
                    }
                });
            }
        });
    }


参考:

一起来造一个RxJava,揭秘RxJava的实现原理

给 Android 开发者的 RxJava 详解



 
 

猜你喜欢

转载自blog.csdn.net/u012674854/article/details/80031767