RxJava2 原始碼解析(一)

mcxtzhang發表於2019-03-03

轉載請標明出處:
juejin.im/post/58c5f8…
本文出自:【張旭童的稀土掘金】(juejin.im/user/56de21…)

概述

最近事情太多了,現在公司內部的變動,自己崗位的變化,以及最近決定找工作。所以部落格耽誤了,準備面試中,打算看一看RxJava2的原始碼,遂有了這篇文章。

不會對RxJava2的原始碼逐字逐句的閱讀,只尋找關鍵處,我們平時接觸得到的那些程式碼。
背壓實際中接觸較少,故只分析了Observable.
分析的原始碼版本為:2.0.1

我們的目的:

  1. 知道源頭(Observable)是如何將資料傳送出去的。
  2. 知道終點(Observer)是如何接收到資料的。
  3. 何時將源頭和終點關聯起來的
  4. 知道執行緒排程是怎麼實現的
  5. 知道操作符是怎麼實現的

本文先達到目的1 ,2 ,3。
我個人認為主要還是介面卡模式的體現,我們接觸的就只有ObservableObserver,其實內部有大量的中間物件在適配:將它們兩聯絡起來,加入一些額外功能,例如考慮dispose和hook等。

從create開始。

這是一段不涉及操作符和執行緒切換的簡單例子:

        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("1");
                e.onComplete();
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "onSubscribe() called with: d = [" + d + "]");
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "onNext() called with: value = [" + value + "]");
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "onError() called with: e = [" + e + "]");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete() called");
            }
        });複製程式碼

拿 create來說,

public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        //.....
        return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
    }複製程式碼

返回值是Observable,引數是ObservableOnSubscribe,定義如下:

public interface ObservableOnSubscribe<T> {
    void subscribe(ObservableEmitter<T> e) throws Exception;
}複製程式碼

ObservableOnSubscribe是一個介面,裡面就一個方法,也是我們實現的那個方法:
該方法的引數是 ObservableEmitter,我認為它是關聯起 Disposable概念的一層:

public interface ObservableEmitter<T> extends Emitter<T> {
    void setDisposable(Disposable d);
    void setCancellable(Cancellable c);
    boolean isDisposed();
    ObservableEmitter<T> serialize();
}複製程式碼

ObservableEmitter也是一個介面。裡面方法很多,它也繼承了 Emitter<T> 介面。

public interface Emitter<T> {
    void onNext(T value);
    void onError(Throwable error);
    void onComplete();
}複製程式碼

Emitter<T>定義了 我們在ObservableOnSubscribe中實現subscribe()方法裡最常用的三個方法。

好,我們回到原點,create()方法裡就一句話return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));,其中提到RxJavaPlugins.onAssembly():

    /**
     * Calls the associated hook function.
     * @param <T> the value type
     * @param source the hook`s input value
     * @return the value returned by the hook
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static <T> Observable<T> onAssembly(Observable<T> source) {
        Function<Observable, Observable> f = onObservableAssembly;
        if (f != null) {
            return apply(f, source);
        }
        return source;
    }複製程式碼

可以看到這是一個關於hook的方法,關於hook我們暫且不表,不影響主流程,我們預設使用中都沒有hook,所以這裡就是直接返回source,即傳入的物件,也就是new ObservableCreate<T>(source).

ObservableCreate我認為算是一種介面卡的體現,create()需要返回的是Observable,而我現在有的是(方法傳入的是)ObservableOnSubscribe物件,ObservableCreateObservableOnSubscribe適配成Observable
其中subscribeActual()方法表示的是被訂閱時真正被執行的方法,放後面解析:

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);
        try {
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }複製程式碼

OK,至此,建立流程結束,我們得到了Observable<T>物件,其實就是ObservableCreate<T>.

到訂閱subscribe 結束

subscribe():

    public final void subscribe(Observer<? super T> observer) {
        ...
        try {
            //1 hook相關,略過
            observer = RxJavaPlugins.onSubscribe(this, observer);
            ...
            //2 真正的訂閱處
            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
            //3 錯誤處理,
            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
            //4 hook錯誤相關,略過
            RxJavaPlugins.onError(e);

            NullPointerException npe = new NullPointerException("Actually not, but can`t throw other exceptions due to RS");
            npe.initCause(e);
            throw npe;
        }
    }複製程式碼

關於hook的程式碼:
可以看到如果沒有hook,即相應的物件是null,則是傳入什麼返回什麼的

    /**
     * Calls the associated hook function.
     * @param <T> the value type
     * @param source the hook`s input value
     * @param observer the observer
     * @return the value returned by the hook
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static <T> Observer<? super T> onSubscribe(Observable<T> source, Observer<? super T> observer) {
        //1 預設onObservableSubscribe(可理解為一個flatmap的操作)是null
        BiFunction<Observable, Observer, Observer> f = onObservableSubscribe;
        //2 所以這句跳過,不會對其進行apply
        if (f != null) {
            return apply(f, source, observer);
        }
        //3 返回引數2
        return observer;
    }複製程式碼

我也是驗證了一下 三個Hook相關的變數,確實是null:

        Consumer<Throwable> errorHandler = RxJavaPlugins.getErrorHandler();
        BiFunction<Observable, Observer, Observer> onObservableSubscribe = RxJavaPlugins.getOnObservableSubscribe();
        Function<Observable, Observable> onObservableAssembly = RxJavaPlugins.getOnObservableAssembly();

        Log.e(TAG, "errorHandler = [" + errorHandler + "]");
        Log.e(TAG, "onObservableSubscribe = [" + onObservableSubscribe + "]");
        Log.e(TAG, "onObservableAssembly = [" + onObservableAssembly + "]");複製程式碼

所以訂閱時的重點就是:

            //2 真正的訂閱處
            subscribeActual(observer);複製程式碼

我們將第一節提到的ObservableCreate裡的subscribeActual()方法拿出來看看:

    @Override
    protected void subscribeActual(Observer<? super T> observer) {
        //1 建立CreateEmitter,也是一個介面卡
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        //2 onSubscribe()引數是Disposable ,所以CreateEmitter可以將Observer->Disposable 。還有一點要注意的是`onSubscribe()`是在我們執行`subscribe()`這句程式碼的那個執行緒回撥的,並不受執行緒排程影響。
        observer.onSubscribe(parent);
        try {
            //3 將ObservableOnSubscribe(源頭)與CreateEmitter(Observer,終點)聯絡起來
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            //4 錯誤回撥
            parent.onError(ex);
        }
    }複製程式碼

Observer是一個介面,裡面就四個方法,我們在開頭的例子中已經全部實現(列印Log)。

public interface Observer<T> {
    void onSubscribe(Disposable d);
    void onNext(T value);
    void onError(Throwable e);
    void onComplete();
}複製程式碼

重點在這一句:

 //3 將ObservableOnSubscribe(源頭)與CreateEmitter(Observer,終點)聯絡起來
            source.subscribe(parent);複製程式碼

sourceObservableOnSubscribe物件,在本文中是:

        new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("1");
                e.onComplete();
            }
        }複製程式碼

則會呼叫parent.onNext()parent.onComplete()parentCreateEmitter物件,如下:

 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) {
            ...
            //如果沒有被dispose,會呼叫Observer的onNext()方法
            if (!isDisposed()) {
                observer.onNext(t);
            }
        }

        @Override
        public void onError(Throwable t) {
            ...
            //1 如果沒有被dispose,會呼叫Observer的onError()方法
            if (!isDisposed()) {
                try {
                    observer.onError(t);
                } finally {
                //2 一定會自動dispose()
                    dispose();
                }
            } else {
            //3 如果已經被dispose了,會丟擲異常。所以onError、onComplete彼此互斥,只能被呼叫一次
                RxJavaPlugins.onError(t);
            }
        }

        @Override
        public void onComplete() {
         //1 如果沒有被dispose,會呼叫Observer的onComplete()方法
            if (!isDisposed()) {
                try {
                    observer.onComplete();
                } finally {
                 //2 一定會自動dispose()
                    dispose();
                }
            }
        }

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

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }
    }複製程式碼

總結重點:

  1. ObservableObserver的關係沒有被dispose,才會回撥ObserveronXXXX()方法
  2. ObserveronComplete()onError() 互斥只能執行一次,因為CreateEmitter在回撥他們兩中任意一個後,都會自動dispose()。根據第一點,驗證此結論。
  3. ObservableObserver關聯時(訂閱時),Observable才會開始傳送資料。
  4. ObservableCreateObservableOnSubscribe(真正的源)->Observable.
  5. ObservableOnSubscribe(真正的源)需要的是發射器ObservableEmitter.
  6. CreateEmitterObserver->ObservableEmitter,同時它也是Disposable.
  7. errorcompletecomplete不顯示。 反之會crash,感興趣的可以寫如下程式碼驗證。
      e.onNext("1");
      //先error後complete,complete不顯示。 反之 會crash
      //e.onError(new IOException("sb error"));
      e.onComplete();
      e.onError(new IOException("sb error"));複製程式碼

一個好玩的地方DisposableHelper

原本到這裡,最簡單的一個流程我們算是搞清了。
還值得一提的是,DisposableHelper.dispose(this);
DisposableHelper很有趣,它是一個列舉,這是利用列舉實現了一個單例disposed state,即是否disposed,如果Disposable型別的變數的引用等於DISPOSED,則起點和終點已經斷開聯絡。
其中大多數方法 都是靜態方法,所以isDisposed()方法的實現就很簡單,直接比較引用即可.
其他的幾個方法,和AtomicReference類攪基在了一起。
這是一個實現引用原子操作的類,物件引用的原子更新,常用方法如下:

//返回當前的引用。
V get()
//如果當前值與給定的expect引用相等,(注意是引用相等而不是equals()相等),更新為指定的update值。
boolean compareAndSet(V expect, V update)
//原子地設為給定值並返回舊值。
V getAndSet(V newValue)複製程式碼

OK,鋪墊完了我們看看原始碼吧:

public enum DisposableHelper implements Disposable {
    /**
     * The singleton instance representing a terminal, disposed state, don`t leak it.
     */
    DISPOSED
    ;

    public static boolean isDisposed(Disposable d) {
        return d == DISPOSED;
    }

    public static boolean dispose(AtomicReference<Disposable> field) {
        //1 通過斷點檢視,預設情況下,field的值是"null",並非引用是null哦!大坑大坑大坑
        //但是current是null引用
        Disposable current = field.get();
        Disposable d = DISPOSED;
        //2 null不等於DISPOSED
        if (current != d) {
            //3 field是DISPOSED了,current還是null
            current = field.getAndSet(d);
            if (current != d) {
            //4 預設情況下 走不到這裡,這裡是在設定了setCancellable()後會走到。
                if (current != null) {
                    current.dispose();
                }
                return true;
            }
        }
        return false;
    }複製程式碼

總結

  1. subscribeActual()方法中,源頭和終點關聯起來。
  2. source.subscribe(parent);這句程式碼執行時,才開始從傳送ObservableOnSubscribe中利用ObservableEmitter傳送資料Observer。即資料是從源頭push給終點的。
  3. CreateEmitter 中,只有ObservableObserver的關係沒有被dispose,才會回撥ObserveronXXXX()方法
  4. ObserveronComplete()onError() 互斥只能執行一次,因為CreateEmitter在回撥他們兩中任意一個後,都會自動dispose()。根據上一點,驗證此結論。
  5. errorcompletecomplete不顯示。 反之會crash
  6. 還有一點要注意的是onSubscribe()是在我們執行subscribe()這句程式碼的那個執行緒回撥的,並不受執行緒排程影響

轉載請標明出處:
juejin.im/post/58c5f8…
本文出自:【張旭童的稀土掘金】(juejin.im/user/56de21…)

相關文章