RxJava2.+創建流程源碼分析

本片文章適用于有一定Android開發經驗并且對于響應式編程有一定了解的程序猿閱讀。

簡介

RxJava按照官方的定義為:一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫。在Android上使用的比較廣泛,因為在移動開發中由于UI線程不能阻塞,否則會出現卡頓,所以異步操作對于移動端編程尤其重要。而RxJava就是這樣一個基于事件流并且便于異步操作的程序庫。下面我們從源碼角度分析一下事件的創建流程。

Demo

Observable observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
               emitter.onNext("hello");
                emitter.onNext("world");
                emitter.onComplete();
            }
        });

Observer observer = new Observer<String>() {
           @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "onSubscribe");
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "onNext data is :" + value);
            }


            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "onError data is :" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete");
            }
        };

observable.subscribe(observer);

輸出:

onSubscribe
onNext data is :hello
onNext data is :world
onComplete

從日志可以看出onSubscribe方法先被調用然后依次輸出hello world 最后輸出 onComplete 符合Observable 中subscribe方法的調用順序。

Observable#create

 @SchedulerSupport(SchedulerSupport.NONE)
    public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        ObjectHelper.requireNonNull(source, "source is null");
        return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
    }

Observable.create()的入參為ObservableOnSubscribe,那ObservableOnSubscribe是什么呢,它是一個接口

public interface ObservableOnSubscribe<T> {

    /**
     * Called for each Observer that subscribes.
     * @param e the safe emitter instance, never null
     * @throws Exception on error
     */
    void subscribe(ObservableEmitter<T> e) throws Exception;
}

ObjectHelper.requireNonNull()對入參進行了空指針判斷。
RxJavaPlugins根據注釋來看其實就是一個對Rxjava標準操作進行處理的插件類。
RxJavaPlugins.onAssembly返回的其實就是new 出來的ObservableCreate對象,同時持有ObservableOnSubscribe對象引用。
那ObservableCreate又是什么呢?其實ObservableCreate就是一個Observable被觀察者對象并重寫了subscribeActual()方法。而subscribeActual()真正調用的地方發生在訂閱發生的地方,下文會分析到。
所以Observable#create最終創建的是ObservableCreate對象。

Observable#subscribe

    @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;
        }
    }

可以看到RxJavaPlugins.onSubscribe(this,observer)其實只是簡單的返回了observer而已,關鍵的是subscribeActual(observer)。通過上文可知,subscribeActual真正發生的地方其實是在ObservableCreate中。

@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);
        }
    }

subscribeActual這段代碼并不長但很重要,咱們一句一句來分析下。
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
采用的是組合的方式,parent 內部持有了observer對象僅此而已,可以理解為parent 為observer的代理。
然后observer調用了自己的onSubscribe方法,這也是為什么我們一開始看到onSubscribe日志最先輸出的原因。同時它也脫離了被訂閱者的管理,因為訂閱者自己調用了自己。
接下來可以看到訂閱真正發生的地方source.subscribe(parent);
source就是一開始我們new出來的ObservableOnSubscribe對象,而parent是訂閱者的代理對象,所以當訂閱發生的時候,就會輸出上面的日子。

單個操作符訂閱總結

1、傳入的ObservableOnSubscribe最終被用來創建成ObservableCreate
2、ObservableCreate持有我們的被觀察者對象以及重新了訂閱觸發時的回調函數subscribeActual
3、在subscribeActual實現了我們的主要邏輯,包括observer.onSubscribe(parent);
source.subscribe(parent);
parent.onError(ex)的調用
4、在Observable的subscribe被調用時開始執行事件分發流程
5、最后放一張對象間的關系圖(此圖來自于網絡)

52eb2279jw1f2rx489robj20lk0a8my2.jpg

組合操作符總結

1、首先我們得明確一點每個操作符最后都會通過RxJavaPlugins.onAssembly(Observable<T> source)返回一個新的Observable。如下:


image.png

2、onAssembly的入參針對每一個操作符都會實現一個繼承自AbstractObservableWithUpstream:Observable的對象,它的作用就是用于包裝上級的AbstractObservableWithUpstream:Observable。比如:


image.png

而每一個新的Observable對象中都會有一個繼承自Observer的對象,它的作用就是用于包裝下級Observer和當前的Function
image.png

3、當我們調用最底層subscribe方法的時候其實真正調用的是上一級Observable的subscribeActual方法,然后subscribeActual方法中會構造一個內部Observer子類的對象,然后通過調用上級Observable的subscribe方法將新生成的包裝Observer對象傳入到上一級中。
4、通過一層層的包裝上傳,當調用鏈來到最頂層的ObservableCreate時,由于不能再往上一層進行封裝了,就會執行ObservableOnSubscribe的subscribe方法,如下:


image.png

而subscribe方法的參數就是下級經過層層包裝傳遞上來的Observer,所以當我們調用emitter的相關方法時,內部都會執行如下操作:


image.png

其中actual就是下級的Observer。
5、當往下的調用鏈來到最底層時自然調用的就是最底層Observer的相關方法了。

至此,組合操作符的調用鏈就分析完了。

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

推薦閱讀更多精彩內容