RxJava(RxAndroid)线程切换机制

  自从项目中使用RxJava以来,可以很方便的切换线程。至于是怎么实现的,一直没有深入的研究过!本篇文章就是分析RxJava的线程模型。
  RxJava基本使用
  先上一个平时使用RxJava切换线程的例子:
  

Observable observable = Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscribersuper String> subscriber) {
                subscriber.onNext("hello");
                subscriber.onCompleted();
            }
        });
        Subscriber subscriber = new Subscriber() {
            @Override
            public void onCompleted() {
                //TODO
            }

            @Override
            public void onError(Throwable e) {
                //TODO
            }

            @Override
            public void onNext(String o) {
                Log.e("RxJava", o);
            }
        };
        observable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(subscriber);

  如果结合Lamda表达式,代码会非常的简洁,为了更直观的分析代码,就没有使用Lamda。通过subscribeOn(Schedulers.io()),
observeOn(AndroidSchedulers.mainThread())轻松的实现线程的切换。非常的简单。下面一步一步分析:
  RxJava主要类
  如果对RxJava有了解的话,都知道它实际是用观察者模式实现的,我们这里只是简单的介绍一下主要的类。
  RxJava(RxAndroid)线程切换机制_第1张图片

  Observable和Subscriber大家已经很熟悉了,分别是被观察者和观察者。在使用RxJava过程中我们一般都是三步,第一步创建Observable,第二部创建Subscriber,第三步通过subscribe()方法达到订阅的目的。为了搞清楚线程切换的实现,必须先搞清楚RxJava内部调用的流程!
  在上边代码中,Observable.create()对应于第一步,会产生一个Observable。那么是怎么创建的呢?而create()方法的源码:
  

public static  Observable create(OnSubscribe f) {
        return new Observable(hook.onCreate(f));
    }

  create()会接收一个OnSubscribe实例,OnSubscribe继承自Action1,有一个call()回调方法。在subscribe()方法执行时会被调用。这里的hook.onCreate()其实其他的什么也没有做就是你传进去什么就返回什么。最后可以看到产生了一个Observable的实例。
  接着看一下subscribe(subscriber) , subscribe()方法会产生订阅行为,接收一个Subscriber实例,现在有了被观察者和观察者,那么我们就可以分析订阅行为了。看subscribe()方法的最终实现:
  

 static  Subscription subscribe(Subscribersuper T> subscriber, Observable observable) {
     // validate and proceed
        if (subscriber == null) {
            throw new IllegalArgumentException("subscriber can not be null");
        }
        if (observable.onSubscribe == null) {
            throw new IllegalStateException("onSubscribe function can not be null.");
            /*
             * the subscribe function can also be overridden but generally that's not the appropriate approach
             * so I won't mention that in the exception
             */
        }

        // new Subscriber so onStart it
        subscriber.onStart();

        /*
         * See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
         * to user code from within an Observer"
         */
        // if not already wrapped
        if (!(subscriber instanceof SafeSubscriber)) {
            // assign to `observer` so we return the protected version
            subscriber = new SafeSubscriber(subscriber);
        }

        // The code below is exactly the same an unsafeSubscribe but not used because it would 
        // add a significant depth to already huge call stacks.
        try {
            // allow the hook to intercept and/or decorate
            hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
            return hook.onSubscribeReturn(subscriber);
        } catch (Throwable e) {
            // special handling for certain Throwable/Error/Exception types
            Exceptions.throwIfFatal(e);
            // in case the subscriber can't listen to exceptions anymore
            if (subscriber.isUnsubscribed()) {
                RxJavaPluginUtils.handleException(hook.onSubscribeError(e));
            } else {
                // if an unhandled error occurs executing the onSubscribe we will propagate it
                try {
                    subscriber.onError(hook.onSubscribeError(e));
                } catch (Throwable e2) {
                    Exceptions.throwIfFatal(e2);
                    // if this happens it means the onError itself failed (perhaps an invalid function implementation)
                    // so we are unable to propagate the error correctly and will just throw
                    RuntimeException r = new OnErrorFailedException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2);
                    // TODO could the hook be the cause of the error in the on error handling.
                    hook.onSubscribeError(r);
                    // TODO why aren't we throwing the hook's return value.
                    throw r;
                }
            }
            return Subscriptions.unsubscribed();
        }
    }

  一般情况下会执行第31行,

hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);

  hook.onSubscribeStart()什么也没有做,将observable.onSubscribe直接返回,那么这句话就可以简化成
  observable.onSubscribe.call(subscriber);
  如果我们没有使用任何的操作符,那么这里的observable.onSubscribe就是我们在create()方法中传入的onSubscribe实例。就会回调其call( subscriber)方法。在call()方法中,我们一般又会根据获得的subscriber引用,去调用相应的onNext()和onComplete()方法。这就是调用的基本流程!
  如果我们使用了例如map这样的操作符,那么基本的流程大致是一样的,只不过是将Observable实例进行相应的变化后,向下传递。最终执行subscribe操作的是最后一个Observable,所以,每个变换后的Observable都会持有上一个Observable 中OnSubscribe对象的引用。
  目前还是没有分析subscribeOn()和observeOn(),接下来就看看他们内部怎么实现的吧!
  subscribeOn()源码:
  

 public final Observable subscribeOn(Scheduler scheduler) {
        if (this instanceof ScalarSynchronousObservable) {
            return ((ScalarSynchronousObservable)this).scalarScheduleOn(scheduler);
        }
        return create(new OperatorSubscribeOn(this, scheduler));
    }

  正如前边所说,这里会产生新的Observable,并且持有上一个Observable的OnSubscribe(我们的例子中就是我们在create()方法中传入的)的引用。我们继续看OperatorSubscribeOn这个类:
  

public final class OperatorSubscribeOn implements OnSubscribe {

    final Scheduler scheduler;
    final Observable source;

    public OperatorSubscribeOn(Observable source, Scheduler scheduler) {
        this.scheduler = scheduler;
        this.source = source;
    }

    @Override
    public void call(final Subscriber subscriber) {
        final Worker inner = scheduler.createWorker();
        subscriber.add(inner);

        inner.schedule(new Action0() {
            @Override
            public void call() {
                final Thread t = Thread.currentThread();

                Subscriber s = new Subscriber(subscriber) {
                    @Override
                    public void onNext(T t) {
                        subscriber.onNext(t);
                    }

                    @Override
                    public void onError(Throwable e) {
                        try {
                            subscriber.onError(e);
                        } finally {
                            inner.unsubscribe();
                        }
                    }

                    @Override
                    public void onCompleted() {
                        try {
                            subscriber.onCompleted();
                        } finally {
                            inner.unsubscribe();
                        }
                    }

                    @Override
                    public void setProducer(final Producer p) {
                        subscriber.setProducer(new Producer() {
                            @Override
                            public void request(final long n) {
                                if (t == Thread.currentThread()) {
                                    p.request(n);
                                } else {
                                    inner.schedule(new Action0() {
                                        @Override
                                        public void call() {
                                            p.request(n);
                                        }
                                    });
                                }
                            }
                        });
                    }
                };

                source.unsafeSubscribe(s);
            }
        });
    }
}

  该类实现了OnSubscribe接口,并且实现了call()方法,也就意味着,我们之前所分析的在subscribe()时,会一步一步去执行observable.onSubscribe.call(),对于SubscribeOn来说他的call()方法的真正实现就是在这里。那么还要注意一点的是这个call()的回调时机,这里要和ObserveOn()做比较,稍后再分析。回到这里的call方法,首先通过外部传入的scheduler创建Worker - inner对象,接着在inner中执行了一段代码,Action0中call()方法这段代码就在worker线程中执行了,也就是此刻线程进行了切换。
  注意最后一句代码source.unsafeSubscribe(s)就是将当前的Observable与上一个Observable通过onSubscribe关联起来。那么如果上一个Observable也是一个subscribeOn()产生的那么会出现什么情况?很显然最终会切换到上一个subscribeOn指定的线程中。例如:
  

  btn_map.setOnClickListener(v -> getObservable()
                .map(integer -> null)
                .subscribeOn(Schedulers.computation())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(integer1 -> Log.e("map", integer1 + "")));

  map的转换实际上会发生在computation线程而不是io线程,换句话说就是设置多个subscribeOn时,实际上只会切换到第一个subscribeOn指定的线程。这一点很重要!!!
  到现在我们已经分析了subscribe()订阅后,一直到回调到我们在create()方法中传入的OnSubscribe的call()方法,subscribeOn()方法是在这个过程中产生作用的。那么ObserveOn呢?看源码:
  

 public final Observable observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        if (this instanceof ScalarSynchronousObservable) {
            return ((ScalarSynchronousObservable)this).scalarScheduleOn(scheduler);
        }
        return lift(new OperatorObserveOn(scheduler, delayError, bufferSize));
    }

  这里经过了一次lift变化,这是个啥玩意呢?
  

public final  Observable lift(final Operatorsuper T> operator) {
        return new Observable(new OnSubscribeLift(onSubscribe, operator));
    }

  实际上也是包装了一层Observable。明白了这一点,在回到observeOn()源码中的OperatorObserveOn。
  

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

  ...省略...

    /**
     * @param scheduler the scheduler to use
     * @param delayError delay errors until all normal events are emitted in the other thread?
     * @param bufferSize for the buffer feeding the Scheduler workers, defaults to {@code RxRingBuffer.MAX} if <= 0
     */
    public OperatorObserveOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        this.scheduler = scheduler;
        this.delayError = delayError;
        this.bufferSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE;
    }

    @Override
    public SubscriberT> call(SubscriberT> child) {
        if (scheduler instanceof ImmediateScheduler) {
            // avoid overhead, execute directly
            return child;
        } else if (scheduler instanceof TrampolineScheduler) {
            // avoid overhead, execute directly
            return child;
        } else {
            ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize);
            parent.init();
            return parent;
        }
    }

    ...省略...

    /** Observe through individual queue per observer. */
    private static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 {

       ...省略...

        @Override
        public void onNext(final T t) {
            if (isUnsubscribed() || finished) {
                return;
            }
            if (!queue.offer(on.next(t))) {
                onError(new MissingBackpressureException());
                return;
            }
            schedule();
        }

        @Override
        public void onCompleted() {
            if (isUnsubscribed() || finished) {
                return;
            }
            finished = true;
            schedule();
        }

        @Override
        public void onError(final Throwable e) {
            if (isUnsubscribed() || finished) {
                RxJavaPlugins.getInstance().getErrorHandler().handleError(e);
                return;
            }
            error = e;
            finished = true;
            schedule();
        } 

         protected void schedule() {
            if (counter.getAndIncrement() == 0) {
                recursiveScheduler.schedule(this);
            }
        }

        ...省略...
    }
}

  安装前文的分析,先看他的call方法,返回了个ObserveOnSubscriber实例,我们需要关注这个实例的onNext方法,很简单,只是执行了schedule()方法,该方法中的recursiveScheduler是在构造方法中根据我们设置的schedule创建的Scheduler.Worker 。

this.recursiveScheduler = scheduler.createWorker();

  线程再次切换了,并且这次是在OnNext()方法中切换的,注意是在OnNext()方法中切换,和subscribeOn()在call中切换是有区别的。这样observeOn设置的线程会影响其后面的流程,直到出现下一次observeOn或者结束。
  这样最基本的线程切换已经搞清楚了,现在我们来分析一下加入例如map这样的操作符的过程:
  

 observable
        .map(str->str+"Rx")
        .map(str1->str1+"Java")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(subscriber);

  根据上边的分析,上一张流程图(不要在意,图很挫):
  RxJava(RxAndroid)线程切换机制_第2张图片
  
  总的来说,RxJava的处理顺序像一条流水线,这不仅仅是代码写起来像一条链上,逻辑上也是如此,也就是说,当你切换流水的流向(线程),整条链都改变了方向,并不会进行分流。理解了这一点,对RxJava的线程切换也就不会感到困难了。

你可能感兴趣的:(Rxjava,RxAndroid)