理解RxJava(一):基本流程源碼分析

最近一直沒有機會,好好寫博客,可能還是太浮躁了,自己對自己的這種狀態也不是特別滿意。近幾日準備安下心來,好好研究一下RxJava,把這期間的所得總結成一個系列,盡量都寫博客中,看看這個階段結束時自己能達到怎么樣的程度。

概述

在日常的Android項目開發中,RxJava+Retrofit是一個萬金油網絡請求框架,通常情況下,我們的代碼大概是這樣的:

 public void requestUserInfo(String userName) {
    serviceManager.getUserInfoService()
                  .getUserInfo(userName)
                  .subscribeOn(Schedulers.io())
                  .observeOn(AndroidSchedulers.mainThread())
                  .subscribe(info -> {
                      //do something
                  });
 }

事實上,我很少去關心RxJava內部是如何實現的,因為這樣我也能夠輕松定制項目中的網絡請求需求,并且寫出看起來還不錯的代碼。

但是很快我就事與愿違了,因為在測試RxJava相關的業務代碼時,面對需要測試的代碼塊,我束手無策,我接連踩到了很多坑。雖然最后我都通過萬能的google一一解決了,但是我已經不滿足現狀,我可以輕易提出很多個讓我疑惑的問題:

1 RxJavaPlugin是干什么的
2 鏈式調用中當存在數個Observable.subscribeOn()時的處理方式
3 鏈式調用中當存在數個Observable.observeOn()時的處理方式
4 數據是如何經過操作符進行的處理
5 各個doOnXXX()方法回調所在的線程?

等等......

于是我就有了這個念頭:研究源碼,徹底將它整明白。

源碼版本

RxJava官方Github: https://github.com/ReactiveX/RxJava

Branch:2.x (RxJava2)

版本號:2.1.3

一.基本流程

我決定從簡單的代碼入手分析RxJava2:

public class RxJavaTest {

    @Test
    public void test() throws Exception {
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onComplete();
             }
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {}

            @Override
            public void onNext(Integer integer) {
                System.out.println(String.valueOf(integer));
            }

            @Override
            public void onError(Throwable e) {}

            @Override
            public void onComplete() {}
        });
    }
}

代碼很簡單,我們可以簡單分成兩步:

1.Observable.create()
2.Observable.subscribe()

一步步進行分析。

二.Observable.create()

我們點擊進入Observable.create()方法的內部:

    public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        //...(表示排除非關鍵代碼,下同)
        return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
    }

可以看到,create方法的返回值仍然是一個Observable,這是當然的,我們看到RxJavaPlugins.onAssembly():


/**
 * Calls the associated hook function.
 */
 public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
    //...
 }

這是一個hook方法,我們暫時先忽略它,默認這個方法就是返回了直接返回source,即傳入的參數對象,那么實際上,create方法的關鍵就是下面這行代碼:

 return new ObservableCreate<T>(source);

來看看這個ObservableCreate是何方神圣:


//1.ObservableCreate是Observable的子類
public final class ObservableCreate<T> extends Observable<T> {

    final ObservableOnSubscribe<T> source;
    
    //2.注意這里,實際上Observable.create方法執行了下面的代碼
    public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }
    
    //3.subscribeActual方法是Observable.subscribe()后才執行的
    @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);
        }
    }
}

我已經把重點標記了,可以得知:

  • 1.ObservableCreate本身就是Observable的子類,因此Observable.create()實際上就是創建并返回一個ObservableCreate對象;
  • 2.在ObservableCreate的構造函數中,實際上是將create()方法中的參數ObservableOnSubscribe依賴注入ObservableCreate中并保存;
  • 3.subscribeActual()方法是在Observable.subscribe()訂閱時執行的,我們先知道這點,一會再詳細介紹它。

現在關于ObservableCreate這個類本身我們基本都了解了,我們來看看我們傳進來的ObservableOnSubscribe是什么:

public interface ObservableOnSubscribe<T> {

    /**
     * Called for each Observer that subscribes.
     */
    void subscribe(@NonNull ObservableEmitter<T> e) throws Exception;
}

原來ObservableOnSubscribe只是一個接口,它就是我們傳進來的這個:


Observable.create(new ObservableOnSubscribe<String>() {
            //就是它
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onComplete();
             }
        }).subscribe(...);

實際上,ObservableOnSubscribe就是讓我們去實現的接口,我們將要發射的事件都通過ObservableEmitter發射器對象進行發射(本文中是依次發射Integer 1、2),可以說,在本文的案例中,ObservableOnSubscribe就是數據流的源頭。

整理思路

現在我們已知的情報,在Observable調用create()方法時:

  • 1.我們實現了ObservableOnSubscribe接口,并在接口的subscribe方法中,傳入了數據源,這些數據源需要通過ObservableEmitter進行發射。
  • 2.在create()方法中,拋開hook不談,實際上方法內部是創建了一個ObservableCreate對象并返回,這個ObservableCreate類本身就是Observable的子類
  • 3.在ObservableCreate的構造方法中,將我們實現的ObservableOnSubscribe(定義事件的發射順序)作為成員保存在ObservableCreate中。

現在基本已經清楚了,但是我們還有兩個問題需要解答:

1.ObservableEmitter發射器對象何時實例化并發射數據?
2.接下來如何才能實現Observable的訂閱?

三.Observable.subscribe()

我們點擊進入查看Observable.subscribe()源碼:

public final void subscribe(Observer<? super T> observer) {
        //...
        try {
            //...
            //1.我們只需要關注下面這行代碼
            subscribeActual(observer);
        } catch (NullPointerException e) {
            throw e;
        } catch (Throwable e) { 
            //...
        }
    }

拋開非核心代碼和hook相關代碼,我們可以看到,當我們調用 Observable.subscribe(observer)方法時,實際上就是調用Observable.subscribeActual(observer)方法。

應該清楚的記得,在本文中,此時執行subscribe()方法的Observable,實際上應該就是ObservableCreate對象。

因此,Observable.subscribe(observer),實際上執行的是下面的代碼:

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) {
        //1.請注意,參數中的observer實際上就是我們要打印onNext的observer
        //2.實例化CreateEmitter對象
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        
        //3.執行observer的onSubscribe方法,這里可以看到:
        //  onSubscribe()回調所在的線程是ObservableCreate執行subscribe()所在的線程
        //  和subscribeOn()/observeOn()無關!
        observer.onSubscribe(parent);

        try {
            //4.ObservableOnSubscribe執行subscribe()方法
            //這個方法就是我們在create()中定義的代碼
            //其實就是發射數據源,parent是CreateEmitter
            source.subscribe(parent);
        } catch (Throwable ex) {
        
            //5.異常處理
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }
}

整理思路

我把需要解釋的基本都放到了注釋中,簡單總結一下流程:

  • 1.在Observable執行subscribe方法時,實際上是執行了ObservableCreate.subscribeActual()方法,并將我們打印數據的回調Observer作為參數傳了進去
  • 2.在subscribeActual方法內部,首先示例化了一個CreateEmitter發射器對象,然后執行Observer的onSubscribe()回調。
  • 3.之后,就是執行一開始我們在代碼中聲明的ObservableOnSubscribe對象的subscribe方法,開始通過CreateEmitter發射器發射數據,即執行:
public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onComplete();
}

現在的問題是,僅僅通過發射器ObservableEmitter.onNext(1),我們需要的打印代碼哪里去了?

Observable.create(//...)
        .subscribe(new Observer<Integer>() {
        
            //...
            
            @Override
            public void onNext(Integer integer) {
                System.out.println(String.valueOf(integer));
            }
            
            //...
        
            
        });

我們拐回到這行代碼:

protected void subscribeActual(Observer<? super T> observer) {
    //...
    
    //2.實例化CreateEmitter對象
    CreateEmitter<T> parent = new CreateEmitter<T>(observer);

    //...
}

我們來看看CreateEmitter這個類:

static final class CreateEmitter<T>
    extends AtomicReference<Disposable>
    
    // 1.請注意,CreateEmitter實現了Disposable接口
    // 這也就說明了在執行上面subscribeActual()步驟3 observer.onSubscribe()的回調時,可以將ObservableEmitter作為參數傳入了
    // ObservableEmitter也是Disposable
    
    implements ObservableEmitter<T>, Disposable {


        private static final long serialVersionUID = -3434801548987643227L;

        final Observer<? super T> observer;
        
        //2.初始化時,會將打印數據的回調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()) {
                //3.在ObservableEmitter.onNext()發射數據時,實際上調用了observer的onNext()回調打印數據
                observer.onNext(t);
            }
        }
        
        // 4(額外):當執行onError()時,會執行dispose()方法取消訂閱
        @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 {
                    observer.onError(t);
                } finally {
                    dispose();
                }
                return true;
            }
            return false;
        }
        
        // 5(額外):當執行onError()時,會執行dispose()方法取消訂閱
        //這也就說明為什么 onComplete()和onError()方法只能觸發其中的一個了
        @Override
        public void onComplete() {
            if (!isDisposed()) {
                try {
                    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());
        }
    }

基本都寫到了注釋中,應該不難理解。

總結

分析一下各個類的職責:

  • Observable :個人理解是裝飾器模式下的基類,實際上所有操作都是Observable的子類進行的實現
  • ObservableOnSubscribe: 接口,定義了數據源的發射行為
  • ObservableCreate: 裝飾器模式的具體體現,內部存儲了數據源的發射事件,和subscribe訂閱事件
  • ObservableEmitter: 數據源發射器,內部存儲了observer
  • Observer: 接收到數據源后的回調(比如打印數據等)

簡單總結一下:

1.Observable.create(),實例化ObservableCreate和ObservableOnSubscribe,并存儲數據源發射行為,準備發射(我已經準備好數據源,等待被訂閱)
2.Observable.subscribe(),實例化ObservableEmitter(發射器ObservableEmitter準備好!數據發射后,數據處理方式Observer已準備好?。?br> 3.執行Observer.onSubscribe()回調,ObservableEmitter作為Disposable參數傳入
4.執行ObservableOnSubscribe.subscribe()方法 (ObservableEmitter發射數據,ObservableEmitter內部的Observer處理數據)

此外我們還可以得到的:

5.CreateEmitter 中,只有Observable和Observer的關系沒有被dispose,才會回調Observer的onXXXX()方法。

6.Observer的onComplete()和onError() 互斥只能執行一次,因為CreateEmitter在回調他們兩中任意一個后,都會自動dispose()。

7.onSubscribe()是在我們執行subscribe()這句代碼的那個線程回調的,并不受線程調度影響。

參考

1.RxJava2 源碼解析(一)@張旭童
http://www.lxweimin.com/p/23c38a4ed360

2.RxJava2 源碼解析——流程 @Robin_Lrange
http://www.lxweimin.com/p/e5be2fa8701c

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容