RxJava進階之源碼分析(part 1)- map() 操作符分析

ncxgf 8年前發布 | 13K 次閱讀 RxJava Android開發 移動開發

終于到了分析源碼的部分了。很多朋友在使用過RxJava之后都會覺得這個庫很玄妙,竟然能把事件發生的源不停的通過不同的操作符改變。比如說這次介紹的map就是,在抽象的概念上,我們經常要求使用者要把map操作符當成改變源stream的一個方法,也就是說map把整個事件的發射流重新構造了一次。

RxJava進階之源碼分析(part 1)- map() 操作符分析

示例圖上面,整個事件流變成了一個完全不一樣的流

但是其實map操作符真的創造了一個新的流么?

RxJava進階之源碼分析(part 1)- map() 操作符分析

肯定不是!

這個答案是非常明顯的,如果RxJava的操作符都是這樣要等源發射流全部分析完再重新構造的話(一個map重新遍歷一次的話),效率上肯定說不過去。所以我們可以肯定一點,即使再多個map(),我們肯定也是一邊發射源stream的元素一邊進行map()里面的轉換的。RxJava并不是一個新的語言,java沒有的它也沒有,一切你們看到的操作符,只是對java現有的一些常用api的整合而已。尤其是我們經常用的subscribeOn,observeOn,map,等等,都只是把引用,線程池,ExecutorService玩耍出來的組合。

當然,我的意思不是說RxJava很簡單。。。。只是作者們在Java的基礎上,非常優雅的把java現有的東西完美的結合起來,使得這個庫使用起來就像函數式編程的感覺。

那RxJava到底是怎么優雅的實現的呢?

在我們深入代碼之前,我們先來補充一些細節:

1.使用鏈式調用產生新對象,優雅的讓新對象持有源對象的引用的。

比如 下面一個例子:

RxJava進階之源碼分析(part 1)- map() 操作符分析

一個優雅的鏈式調用

大家可以看到line 13,這個方法generateNext()返回了一個新的Ob對象,但是把自己-this,傳給了新生成的對象,新的對象就獲取了源對象的引用了。于是在我不斷的鏈式調用方法generateNext()的時候,雖然最后獲取的是最后一個Ob對象,但是我的新對象已經擁有一條完整的,通向源對象的鏈了。不同于以往我們一般的setNext()這種方法,generateNext()返回一個新的Ob對象,所以程序可以以一個鏈式的結構寫出來。

這里可以提前告訴大家,RxJava里面的Observable就是這樣的,每一次鏈式的調用操作符,比如map,返回的都是一個新的Observable,而新的Observable是持有舊的Observable的引用的(其實也不是整個Observable,是Observable的一個成員對象)。

 

2.一個Observable所需要的元素

一個Observable需要兩個最重要的元素,一個是OnSubscribe對象,一個是Subscriber。前者負責定義整個Observable所要執行的action,后者則是定義怎樣處理每一個發射的元素,一般來說后者都是用戶自己實現的。

比如以下例子:

RxJava進階之源碼分析(part 1)- map() 操作符分析

發射1,2

這個例子很簡單,我們創建了一個發射數字1和2的流,在create方法里面,我們創建了一個新的對象OnSubscribe,它定義了我們的事件發生的順序的元素的個數種類。而subscribe()方法里面我們創建了一個新的Subscriber對象。讓我們看看create()方法做了些啥。

RxJava進階之源碼分析(part 1)- map() 操作符分析

step1

RxJava進階之源碼分析(part 1)- map() 操作符分析

step2

僅僅是return了一個Observable,然后把OnSubscribe對象的引用拿到手而已。

然后每次我們call subscribe()方法的時候發生了啥呢?我們把代碼跟蹤到subscribe(),

RxJava進階之源碼分析(part 1)- map() 操作符分析

注意line 8191

RxJava進階之源碼分析(part 1)- map() 操作符分析

不是很清楚這個hook的意義,但是不影響我們理解

看到了嘛?每次在subscribe()的時候,我們會調用我們Observable里面的onSubscribe對象的call方法,參數就是我們傳進subscribe()的subscriber對象(當然嚴格意義上來講并不是同一個subscriber,subscribe()方法在前面一點的地方稍微包裝了一下我們傳進的subscriber,但是我們可以理解為同一個)。

RxJava進階之源碼分析(part 1)- map() 操作符分析

可以理解為一個subscriber

所以總結一句,每一個要發射元素的Observable,都必須會有一個OnSubscribe對象和Subscriber。前者定義執行的順序、事件,后者處理。

 

3.分析!

ok,在了解了這些先決知識之后,我們可以深入分析map到底是怎么工作的了。

RxJava進階之源碼分析(part 1)- map() 操作符分析

把一個新的OperatorMap傳進lift()

RxJava進階之源碼分析(part 1)- map() 操作符分析

lift的重點在于生成新的subscriber,把它傳進上一個Observable的OnSubscribe對象,line 162

讓我們重點看看圖2,lift()方法生成了一個新的Observable,新的Observable是干嘛的?

1.新的Observable的OnSubscribe對象的call()方法里面,我們把用戶定義的Subscriber對象,line 156-158 ,通過我們的轉換操作符map,轉換成了一個新的subscriber

2.生成新的subscriber,傳給上一個Observable的onSubscribe對象執行call(). 大家一定要仔細看清楚,line 162的這個OnSubscribe,是新的Observable的對象還是舊的Observable的對象。

簡單的用圖來解釋一下可能更清楚:

RxJava進階之源碼分析(part 1)- map() 操作符分析

新生成的Observable會在用戶call subscribe()的時候,把原有的,用戶自己定義的subscriber修改了之后(lift()里面做的),傳給上一個Observable的OnSubscribe對象處理。

 

那么在第一步的時候,我們對用戶原有的subscriber動了什么手腳?

這是第二重要的點,用戶原有的subscriber會在lift()里面,被map這個Operator改造

RxJava進階之源碼分析(part 1)- map() 操作符分析

改造了!

這個Operator就是OperatorMap。讓我們看看這個Operator的call方法究竟做了些啥,讓原有的subscriber變成一個怎樣的新的subscriber。

RxJava進階之源碼分析(part 1)- map() 操作符分析

很簡單有木有!

乍一看!好簡單。

的確,map這個操作符的確很簡單,讓我們來看看它把原來的,用戶定義的subscriber怎么改造了。

1.line 39, 我們可以看到call()方法返回一個新的subscriber

2.line 54, 這個o對象是啥?沒錯,就是原來舊的subscriber,用戶自己創建的subscriber。

3.line 54,  transformer就是我們轉換的方法,也就是map()里面的Func1對象。

也就是說,新的subscriber每次在執行onNext的時候,其實是把上一層Observable發射的元素先用map里面在轉換方程轉換成新的類型,然后再用下一層的subscriber去發射新的類型的元素。

比如我們把一組Integer轉換成String對象,在上圖里面的新的Subscriber的泛型T就是Integer,舊的Susbcriber(用戶自己定義的Subscriber)的泛型就是R。

這里就很有意思了,這個過程里面發生了很多有趣的事情。

我們在subscribe()之后,會把原有的subscriber不停的包裝,每map()一次就會包裝一次,一路傳給最頂端,最原始的Observable,然后在發射元素的時候,會不停的調用轉化方程,發送給下一級的subscriber。

為什么說這個過程很有趣呢?有趣的地方在于,這個過程像在爬山一樣,最開始我們要一路往上走,最下面的Observable持有上一層的Observable的引用,而在最頂端的原始Observable要發射元素的時候,subscriber已經是包裝過好多層的subscriber了,執行onNext() 的時候,會一路往下調用下一層的subscriber的onNext().,所以回到我們在文章最開頭講的,每一次一個元素在發射之后,我們會即刻執行該元素的轉換(也就是不停的執行下一級的onNext()),而不是重新構造一個新的流。

換句話說,Observable的執行鏈一路向上,Subscriber的執行鏈一路向下,他們產生鏈的方向恰好是相反的。

不過想想也是合情合理的,因為從邏輯上來講,我們create的一個Observable的是一個原始的Observable,只擁有原始數據,但是用戶卻是提供的一個不同參數類型的,最終類型版本的Subscriber,原本方向就是相反的。

 

讓我們再把思維拓展一下,發生多層map的過程是咋樣的:

 

RxJava進階之源碼分析(part 1)- map() 操作符分析

下上下!

再看完整篇文章之后,再來體會一下這張圖,是不是豁然開朗了呢?產生新的Observable向下,產生新的Subscriber向上,執行onNext向下。

 

三個字總結,

下上下!

RxJava進階之源碼分析(part 1)- map() 操作符分析

下上下!搓出了大招!

創建新的Observable一路向下,創建新的Subscriber一路向上,最后每次發射元素的時候一路向下直到到達用戶創建的subscriber為止。

希望大家能好好理解一下這里設計的精妙之處。下周會帶來subscribeOn()操作符的源碼講解。


 

文/qing的世界(簡書作者)
原文鏈接:http://www.jianshu.com/p/414865a88abf
 

 本文由用戶 ncxgf 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!