使用Rxjava進(jìn)行切換線程很簡(jiǎn)單递瑰,一行代碼讓耗時(shí)操作去子線程執(zhí)行,再來(lái)一行代碼回主線程進(jìn)行結(jié)果監(jiān)聽(tīng)隙畜。
那么問(wèn)題就來(lái)了抖部,Rxjava 是怎么實(shí)現(xiàn)的線程切換呢?
腦海里的答案是什么议惰?
線程池 or Handler 還是什么慎颗?
emmmmm,這個(gè)答案 只對(duì)了一半
我的答案是:
耗時(shí)操作、主線程操作俯萎。確實(shí)是線程池和handler傲宜。但是具體的切換操作是 Scheduler。它是個(gè)抽象類夫啊,把耗時(shí)操作函卒、結(jié)果監(jiān)聽(tīng) ,包裝成 Runnable撇眯。丟到Scheduler的實(shí)現(xiàn)類去執(zhí)行报嵌。
為什么說(shuō)Rxjava的線程切換是由Scheduler完成的呢?
來(lái)叛本,從源碼中找答案的支撐沪蓬。
閱讀建議:rxjava代碼比較繞,建議靜下心來(lái)来候,打著斷點(diǎn)一步步看跷叉。
首先來(lái)看一段代碼(圖1)
通過(guò)調(diào)用subscribeOn() 和observeOn 方法,完成了線程的切換营搅。
眾所周知云挟,RxJava是出了名的繞。為了方便分析转质,將(圖1)進(jìn)行代碼拆分(圖2)园欣。
testRxjavaThreadSwitch2 中的代碼塊調(diào)度邏輯與testRxjavaThreadSwitch1 完成相等。
分析前我們要先定下分析的方法(圖3所示)休蟹。
代碼的調(diào)用鏈?zhǔn)怯梢坏剿牟浇M合而成沸枯。鏈的關(guān)鍵在第四步。沒(méi)有進(jìn)行subscribe的話赂弓,這段Rxjava 代碼是不會(huì)執(zhí)行绑榴。代碼真正的執(zhí)行又是從第四步,一步步的封裝打包盈魁。傳遞到第一步去翔怎。
可以理解為是U型結(jié)構(gòu)。
代碼鏈的分析:
分析第一步杨耙。Observable.create方法赤套。點(diǎn)到源碼中去看
總結(jié): 真正的實(shí)現(xiàn)類是ObservableCreate。持有的對(duì)象source是我們穿進(jìn)去的 接口類ObservableOnSubscribe珊膜。
第二步:create.subscribeOn的源碼
總結(jié):因?yàn)榈谝徊降膶?shí)現(xiàn)類是ObservableCreate容握,所以create.subscribeOn 實(shí)際是
ObservableCreate.subscribeOn。 返回的函數(shù) new ObservableSubscribeOn<>(this, scheduler) 中的this 是 ObservableCreate對(duì)象车柠,scheduler 是我們傳入的
Schedulers.computation()唯沮。所以第二步的實(shí)現(xiàn)類是ObservableSubscribeOn脖旱。
第三步:
observableonSubscribeOn.observeOn的源碼:
總結(jié):第二步的實(shí)現(xiàn)類是ObservableSubscribeOn堪遂。所以
observableonSubscribeOn.observeOn的調(diào)用實(shí)際是ObservableSubscribeOn.observeOn介蛉。返回函數(shù)new ObservableObserveOn<>(this, scheduler, delayError, bufferSize)。中的this是ObservableSubscribeOn溶褪,scheduler是我們傳入的AndroidSchedulers.mainThread()币旧。
因此,第三步的實(shí)現(xiàn)類是ObservableObserveOn
第四步:
observableObserveOn.subscribe的源碼:
總結(jié):因?yàn)槲覀冎粋魅肓艘粋€(gè)Consumer猿妈,所以Rxjava為我們補(bǔ)齊了onError和onComplete
第三步的實(shí)現(xiàn)類是ObservableObserveOn吹菱。所以第四步的
observableObserveOn.subscribe的調(diào)用實(shí)際是
ObservableObserveOn.subscribe。
至此彭则,調(diào)用鏈串聯(lián)完成鳍刷。讓我們回顧總結(jié)下代碼真實(shí)調(diào)用。
第一步:Observable.create 方法構(gòu)造個(gè)ObservableCreate作為返回對(duì)象
第二步:
ObservableCreate.subscribeOn 構(gòu)造ObservableSubscribeOn作為返回對(duì)象
第三步:
ObservableSubscribeOn.observeOn 構(gòu)造ObservableObserveOn作為返回對(duì)象
第四步:
ObservableObserveOn.subscribe俯抖。調(diào)用subscribe输瓜,rxjava代碼鏈 成!芬萍!開(kāi)始執(zhí)行尤揣。
執(zhí)行鏈的分析:
我們先看一段代碼:
抽象類 Observable。是 第一二三步實(shí)現(xiàn)類ObservableCreate柬祠、ObservableSubscribeOn北戏、ObservableObserveOn的父類,當(dāng)在實(shí)現(xiàn)類中調(diào)用(圖9)中的subscribe方法漫蛔。實(shí)際是執(zhí)行到了 Observable類中的subscribe嗜愈。由subscribe方法來(lái)進(jìn)行各種驗(yàn)證,然后調(diào)用subscribeActual來(lái)進(jìn)行統(tǒng)一分發(fā)到實(shí)現(xiàn)類中莽龟,去做具體的實(shí)現(xiàn)行為蠕嫁。
讓我們回顧第四步:
一次包裝:
(圖10)所示,將我們傳入的Consumer包裝成LambdaObserver轧房。然后傳遞ObservableObserveOn中的subscribeActual執(zhí)行拌阴。代碼運(yùn)行起來(lái)打個(gè)斷點(diǎn)驗(yàn)證下
二次包裝:
在(圖11)中我們可以看到第四步的Consumer包裝類LambdaObserver傳遞了過(guò)來(lái)。
再把LambdaObserver包裝成ObserveOnObserver(二次包裝)奶镶。ObserveOnObserver持有 LambdaObserver和我們傳入的AndroidSchedulers迟赃。交給source(第二步的實(shí)現(xiàn)類)ObservableSubscribeOn 執(zhí)行。
三次包裝:
(圖12)所示厂镇,第二次包裝的ObserveOnObserver包裝成SubscribeOnObserver纤壁。
這個(gè)時(shí)候要注意了!^嘈拧W妹健G烦铡!C胱伞@伞!S晗F凶伞!6咐濉3槊住!2谥谩T迫住!0埂1贽唷!网持!
scheduler.scheduleDirect(newSubscribeTask(parent))
這行代碼標(biāo)識(shí)宜岛,我們層層包裝的observer?(SubscribeOnObserver->ObserveOnObserver->LambdaObserver->Consumer)。要包裝成SubscribeTask(繼承了Runnable接口) 這個(gè)Runnable功舀,交給scheduler調(diào)度萍倡。
看(圖14)的紅圈,代碼已經(jīng)到子線程執(zhí)行了辟汰。
加快我們的分析列敲。run代碼塊中的source 是ObservableCreate,而parent對(duì)象則是我們層層包裹的observer帖汞。按照老方法戴而。下一步會(huì)執(zhí)行到
ObservableCreate.subscribeActual。
四次包裝:
看這個(gè)傳入的observer翩蘸。是不是我們上層包裝的observer所意。到了這層 會(huì)在次包裝。包裝后的效果(CreateEmitter->SubscribeOnObserver->ObserveOnObserver->LambdaObserver->Consumer)催首。還記得我們代碼鏈分析的第一步嗎扶踊?(圖15)中的source,是我們傳入的ObservableOnSubscribe接口類郎任。
在回到我們的測(cè)試代碼
(圖16)中箭頭指向的it秧耗,也就是我們所常見(jiàn)的發(fā)射器emitter。就是我們經(jīng)過(guò)四次包裝舶治,最終生成的CreateEmitter分井。
至此车猬,切換到子線程的邏輯,跑通了3呙V槿颉!K豸铩V酢!
說(shuō)了這么多杭朱。才跑通了切換到子線程。是不是已經(jīng)進(jìn)入混沌狀態(tài)了吹散。
我們?cè)诳偨Y(jié)下關(guān)鍵點(diǎn):
Rxjava弧械,會(huì)按照我們代碼書寫順序生成個(gè)調(diào)用鏈,最后的subscribe方法標(biāo)志著調(diào)用鏈形成空民。然后從下往上刃唐,把Consumer經(jīng)過(guò)層層包裝。傳遞到頂層作為emitter發(fā)射器的實(shí)現(xiàn)類界轩。其中會(huì)在
ObservableSubscribeOn.subscribeActual方法中画饥,生成個(gè)SubscribeTask的Runnable。將代碼的執(zhí)行切換到子線程浊猾。
我們繼續(xù)抖甘,攻堅(jiān)最后一步。子線程在切換到主線程葫慎。
在觀察(圖16)衔彻,發(fā)射器調(diào)用了it.onNext("111111")。因?yàn)榘l(fā)射器的實(shí)現(xiàn)類是CreateEmitter偷办。
還記得通過(guò)四次包裝的observer嗎艰额?接下來(lái)我們拆快遞了(CreateEmitter->SubscribeOnObserver->ObserveOnObserver->LambdaObserver->Consumer)〗费模快遞長(zhǎng)這樣柄沮。
剩下的就不一步步分析了,打著斷點(diǎn)一步步跟就行废岂。接下來(lái)只分析關(guān)鍵點(diǎn)祖搓。拆快遞拆到ObserveOnObserver層,看(圖18)
經(jīng)過(guò)onNext的調(diào)用后泪喊,執(zhí)行schedule()方法棕硫,交給worker進(jìn)行調(diào)用,worker是我們傳入的
AndroidSchedulers.mainThread()袒啼。實(shí)現(xiàn)類是HandlerScheduler哈扮。
(圖19)中的紅框纬纪,老哥們看了都會(huì)懂吧!此時(shí)還在子線程執(zhí)行呢滑肉。馬上要把我們的數(shù)據(jù)包裝成ScheduledRunnable作為個(gè)message包各,傳遞到handler中執(zhí)行了。
當(dāng)包裝的ScheduledRunnable的run執(zhí)行的時(shí)候代表什么靶庙?问畅??
代表已經(jīng)回到主線程了六荒。后續(xù)的代碼執(zhí)行會(huì)繼續(xù)進(jìn)行對(duì)observer拆包护姆。最終把數(shù)據(jù)回調(diào)到我們subscribe傳入的Consumer中。
至此我們這篇文章的探索的Rxjava線程切換原理掏击。在源碼層需要找尋的答案卵皂,已經(jīng)找到了。
最后的最后在總結(jié)下砚亭。
Rxjava灯变,會(huì)按照我們代碼書寫順序生成個(gè)調(diào)用鏈,最后的subscribe方法標(biāo)志著調(diào)用鏈形成捅膘。然后從下往上添祸,把Consumer經(jīng)過(guò)層層包裝。傳遞到頂層作為emitter發(fā)射器的實(shí)現(xiàn)類寻仗。其中會(huì)在
ObservableSubscribeOn.subscribeActual方法中刃泌,生成個(gè)SubscribeTask的Runnable。將代碼的執(zhí)行切換到子線程愧沟。
發(fā)射器emitter調(diào)用onNext蔬咬,開(kāi)始對(duì)Consumer的包裝進(jìn)行拆包。當(dāng)拆包拆到ObserveOnObserver層時(shí)沐寺。會(huì)有個(gè)worker調(diào)度林艘,也就是開(kāi)始文章開(kāi)篇說(shuō)的Scheduler。生成個(gè)Runnable的message交給handler分發(fā)混坞。將代碼的執(zhí)行切換到主線程狐援。
在總結(jié)的精煉點(diǎn):
Rxjava,通過(guò)把要切換線程的任務(wù)包裝成Runnable交給Scheduler調(diào)度。具體是線程池或handler,交由Scheduler實(shí)現(xiàn)類實(shí)現(xiàn)究孕。
寫在最后啥酱。Rxjava源碼很繞很復(fù)雜。當(dāng)我們耐心跑通一個(gè)流程后厨诸,其他的各種操作符的理解都會(huì)變得容易起來(lái)镶殷。耐下心來(lái),細(xì)讀源碼微酬,與大神在不同時(shí)空的思想碰撞绘趋,獲益良多颤陶。