四. RxJava之基本原理

jasonhww發表於2019-02-24

不忘初心 砥礪前行, Tomorrow Is Another Day !

本文概要:

  1. Observable的建立
  2. subscribe訂閱過程
  3. 傳送事件
  4. 執行緒切換過程

1. Observable的建立

對應原始碼

//Observable.java
@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        //引數檢查
        ObjectHelper.requireNonNull(source, "source is null");
        //裝配Observable,返回一個ObservableCreate物件
        return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
    }

//鉤子方法
    @NonNull
    public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
        Function<? super Observable, ? extends Observable> f = onObservableAssembly;
        if (f != null) {
            return apply(f, source);
        }
        return source;
    }
    
     @NonNull
    static <T, R> R apply(@NonNull Function<T, R> f, @NonNull T t) {
        try {
            return f.apply(t);
        } catch (Throwable ex) {
            throw ExceptionHelper.wrapOrThrow(ex);
        }
    }

複製程式碼

當我們通過Create方法建立一個Observable物件時,

  • 引數檢查,然後裝配Observable,返回一個ObservableCreate物件,它持有一個ObservableOnSubscribe物件,ObservableCreate是Observable的子類
    • 裝配流程: 執行鉤子方法,對即將建立的Observale進行預處理,可以通過onObservableAssembly進行設定.

2. subscribe訂閱過程

當我們建立完Observable物件時,會呼叫subscribe去繫結觀察者Observer.所以直接看該方法.

對應原始碼

//Observable.java
@SchedulerSupport(SchedulerSupport.NONE)
    @Override
    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;
        }
    }
複製程式碼

同樣的方式,對我們傳入的Observer觀察者物件進行檢查以及預處理,最終呼叫subscribeActual方法,該方法是一個抽象方法.所以我們直接看它的實現類,也就是ObservableCreate物件下的subscribeActual方法.

對應原始碼

//ObservableCreate.java

public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }

@Override
    protected void subscribeActual(Observer<? super T> observer) {
        //1. 建立一個發射器物件
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        //2. 回撥onSubscribe,通知訂閱成功
        observer.onSubscribe(parent);

        try {
            //3. 回撥subscribe,開始傳送事件.
            //source物件就是建立被觀察者傳入的.
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }
複製程式碼

上面註釋已經寫得很詳細了這裡再重複一次.整個訂閱過程就是.

  1. 建立一個發射器物件,繫結觀察者Observer
  2. 回撥onSubscribe,通知訂閱成功
  3. 回撥subscribe,開始傳送事件

接著我們來看發射器物件CreateEmitter是如何將事件傳送給訂閱者的.

3. 傳送事件

對應原始碼

//ObservableCreate#CreateEmitter.java
static final class CreateEmitter<T>
    extends AtomicReference<Disposable>
    implements ObservableEmitter<T>, Disposable {


        private static final long serialVersionUID = -3434801548987643227L;

        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()) {
                //回撥onNext
                observer.onNext(t);
            }
        }

        @Override
        public void onError(Throwable t) {
            if (!tryOnError(t)) {
                RxJavaPlugins.onError(t);
            }
        }

        @Override
        public boolean tryOnError(Throwable t) {
            if (t == null) {
                t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
            }
            if (!isDisposed()) {
                try {
                    //回撥onError
                    observer.onError(t);
                } finally {
                    //最後斷開訂閱
                    dispose();
                }
                return true;
            }
            return false;
        }

        @Override
        public void onComplete() {
            if (!isDisposed()) {
                try {
                    //回撥onComplete.
                    observer.onComplete();
                } finally {
                    //最後斷開訂閱
                    dispose();
                }
            }
        }

        @Override
        public void setDisposable(Disposable d) {
            DisposableHelper.set(this, d);
        }

        @Override
        public void setCancellable(Cancellable c) {
            setDisposable(new CancellableDisposable(c));
        }

        @Override
        public ObservableEmitter<T> serialize() {
            return new SerializedEmitter<T>(this);
        }

        @Override
        public void dispose() {
            DisposableHelper.dispose(this);
        }

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }
    }
    

    //DisposableHelper.java
    //斷開訂閱方法
    public static boolean dispose(AtomicReference<Disposable> field) {
        Disposable current = field.get();
        Disposable d = DISPOSED;
        if (current != d) {
            current = field.getAndSet(d);
            if (current != d) {
                if (current != null) {
                    current.dispose();
                }
                return true;
            }
        }
        return false;
    }

    
複製程式碼

從上面註釋可知,發射器CreateEmitter直接回撥了觀察者Observer的相關方法.當呼叫dispose斷開dispose訂閱時,此時和執行緒中斷處理一樣,僅僅只是作為一個標識,標識當前發射器已經被中斷.

這裡最後給出一張關係圖對上面流程進行歸納.

四. RxJava之基本原理
Observable的建立-訂閱-傳送事件過程

4. subscribeOn過程

從上面可知,RxJava的整體流程框架還是挺清晰的,但有時我們需要多它進行一些附加的操作如切執行緒,map,filter進行轉換等.這裡以切執行緒為例進行分析看如何工作的.

@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        //新建一個ObservableSubscribeOn.
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
    }

複製程式碼

當我們切換下游執行緒時,也返回了一個新建的Observable-ObservableSubscribeOn.接著我們直接看ObservableSubscribeOn類.

對應原始碼

//ObservableSubscribeOn.java
//中間的Observable.
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
        super(source);//上游的源Observable
        this.scheduler = scheduler;
    }

@Override
    public void subscribeActual(final Observer<? super T> s) {
        //建立一箇中間的Observer
        //建立一箇中間的Observer
        //建立一箇中間的Observer
        //重要的話說三遍.
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
        //回撥onSubscribe,通知訂閱成功
        s.onSubscribe(parent);
        
        //切換執行緒
        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }
    
//執行緒任務類SubscribeTask    
final class SubscribeTask implements Runnable {
        private final SubscribeOnObserver<T> parent;

        SubscribeTask(SubscribeOnObserver<T> parent) {
            this.parent = parent;
        }

        @Override
        public void run() {
            //回撥subscribe,進行訂閱
            //source是源Observable,parent則是中間Observer,不是最終目標的Observer.這裡一定要清楚.
            source.subscribe(parent);
        }
    }    
複製程式碼

從上面註釋可知,當我們呼叫subscribeOn切換上游執行緒時

  1. 建立一箇中間的Observable,然後在這個Observable裡面會建立一箇中間的Observer
  2. 最後線上程任務的run方法裡面通過將源Observable與中間的Observer進行繫結訂閱,從而進行切換了上游執行緒.
  3. 中間的Observer接到相應回撥時則會繼續往上回撥源Observer.

這也就是解釋了最開始文章所說的subscribeOn無論呼叫幾次,為什麼只有第一次是生效的.因為每次都建立新的Observable與Observer,執行緒排程器裡將源Observable與中間的Observer進行繫結訂閱時,源Observable僅僅是指上一個,已經不是第一個建立出來的.

通過上面流程分析可以總結出RxJava操作符一些通用的流程.對於Map等操作符都可以參考.如圖

四. RxJava之基本原理
Observable附加操作通用流程

5. observeOn過程

最後我們根據上面總結出的通用流程,去分析下切換下游執行緒的過程.


@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        ObjectHelper.verifyPositive(bufferSize, "bufferSize");
        //返回一個新建的Observable
        return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
    }

複製程式碼

同樣當呼叫observeOn過程切換下游執行緒時,果不其然也返回了一箇中間的Observable-ObservableObserveOn.接著看ObservableObserveOn程式碼.

對應原始碼

//中間的Observable
//ObservableObserveOn.java
@Override
    protected void subscribeActual(Observer<? super T> observer) {
        if (scheduler instanceof TrampolineScheduler) {
            source.subscribe(observer);
        } else {
            //執行緒排程器
            Scheduler.Worker w = scheduler.createWorker();
            //回撥subscribe進行訂閱(中間的Observer-ObserveOnObserver)
            source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
        }
    }
複製程式碼

同樣,果不其然

  1. 建立了一箇中間的Observer-ObserveOnObserver,這個中間的Observer繫結了執行緒排程器Scheduler.
  2. 接著將源Observable與它繫結訂閱.
  3. 最後接收到事件時,則通過中間Observer的執行緒排程器去回撥目標Observer.

之前我們知道每次執行observeOn都會切換一次下游執行緒,從上面原始碼可知,每次都會新建一箇中間的Observer繫結新指定的執行緒排程器,所以接收事件都是在新的執行緒中執行啦.

至此,RxJava基本原理就差不多分析完成,最重要的是記住兩張流程圖,都遵循這個規律.

由於本人技術有限,如有錯誤的地方,麻煩大家給我提出來,本人不勝感激,大家一起學習進步.

相關文章