RxJava進(jìn)階之源碼分析(part 3)- observeOn() 操作符分析

隔了好久,終于有時(shí)間更新一下RxJava進(jìn)階的最后一篇文章了获三。前幾個(gè)星期有幸參加了今年的Google I/O(谷歌舉辦的一年一度的開(kāi)發(fā)者大會(huì)食绿,今年在谷歌總部舉行),去了一趟迷人的加州磕潮,于是文章被拖延了翠胰。有興趣的朋友可以看看我上一篇類(lèi)似于日志的google之行文章。

五月自脯,Google I/O 之行

上一次我們介紹了subscribeOn操作符的源碼之景,那么這一次回到正題,把observeOn操作符的用法和源碼過(guò)一遍膏潮。

我們先看看這個(gè)例子:

轉(zhuǎn)換很簡(jiǎn)單锻狗,我們先發(fā)射1,2焕参,3這三個(gè)數(shù)字轻纪,在IO線(xiàn)程進(jìn)行第一次轉(zhuǎn)換,在computation線(xiàn)程進(jìn)行第二次轉(zhuǎn)換龟糕,最后在newThread線(xiàn)程進(jìn)行打印桐磁。我們來(lái)觀(guān)察一下打印結(jié)果。大家可以根據(jù)自己對(duì)observeOn操作符的理解先預(yù)測(cè)一下讲岁。(注意我在發(fā)射元素的地方進(jìn)行了sleep操作我擂,暫停當(dāng)前線(xiàn)程一秒鐘,原因之后會(huì)解釋)

按照我們之前對(duì)map操作符的理解缓艳,這組操作應(yīng)該會(huì)是把對(duì)數(shù)字1先后進(jìn)行轉(zhuǎn)換1校摩,轉(zhuǎn)換2,打印阶淘,然后在對(duì)2做同樣的操作衙吩。

那么我們來(lái)看看結(jié)果是否是這樣?

終于預(yù)測(cè)正確了一次

哈哈溪窒,終于坤塞,我們這次預(yù)測(cè)對(duì)了。的確是按照我們事前所想的那樣把三個(gè)數(shù)字分別打印出來(lái)的澈蚌。observeOn操作符的作用也正是如此摹芙,每次使用observeOn,都會(huì)把這個(gè)observeOn下面的操作包裝在該observeOn指定的線(xiàn)程池中運(yùn)行宛瞄。

還記得上一篇講過(guò)的subscribeOn操作符嘛浮禾,subscribeOn只能作用一次,而observeOn可以作用多次。原因我們接下來(lái)也會(huì)講盈电。

那么我們跟蹤源碼蝴簇,由于我們之前幾篇已經(jīng)講過(guò)RxJava的lift方法和大概的工作原理,這篇我就不多說(shuō)lift的具體作用匆帚,假設(shè)大家已經(jīng)了解相關(guān)知識(shí)了熬词,如果不了解的請(qǐng)從map的源碼分析開(kāi)始。

observeOn操作符會(huì)用OperatorObserveOn改變?cè)械腟ubscriber(大家應(yīng)該還記得原有的subscriber是從哪來(lái)的吧吸重?沒(méi)錯(cuò)這里說(shuō)的原有的subscriber就是從下一級(jí)傳上來(lái)的subscriber)荡澎。

OperatorObserveOn

在這個(gè)操作符的call方法里面(大家還記得lift方法會(huì)用操作符的call方法改變?cè)衧ubscriber對(duì)吧?)晤锹,生成新的Susbcriber,ObserveOnSubscriber

新的Subscriber里面彤委,結(jié)構(gòu)有點(diǎn)點(diǎn)復(fù)雜鞭铆,有一個(gè)隊(duì)列,然后把原有的subscriber的引用傳進(jìn)來(lái)焦影,作為自己的成員對(duì)象车遂。

新的subscriber

新的subscriber里面,我們重點(diǎn)關(guān)注onNext()方法做了些啥斯辰,因?yàn)槊看伟l(fā)射元素舶担,都是先調(diào)用新的subscriber的onNext()方法的。

新的onNext方法會(huì)先把我們發(fā)射的原始元素添加到隊(duì)列里面(line129),如果發(fā)生錯(cuò)誤彬呻,執(zhí)行onError衣陶,并且返回(line 130 - 131)。假如添加元素成功闸氮,執(zhí)行schedule()剪况。

在創(chuàng)建了一個(gè)新的Action對(duì)象之后,我們把對(duì)象放入一個(gè)Scheduler里面執(zhí)行了蒲跨。如果大家還記得上一篇文章的內(nèi)容译断,應(yīng)該了解這個(gè)Action和Scheduler的關(guān)系。類(lèi)似于Java里面Runnable對(duì)象和ExecutorService一樣或悲,最后Action里面的操作會(huì)被放入線(xiàn)程池孙咪,尋找合適的線(xiàn)程執(zhí)行。

所以其實(shí)最后兜兜轉(zhuǎn)轉(zhuǎn)巡语,最重要的翎蹈,需要執(zhí)行的方法就是這個(gè)pollQueue(),這個(gè)方法從名字就可以看得出來(lái)是要獲取隊(duì)列元素了。而事實(shí)也的確如此捌臊,我們看看pollQueue方法里面最重要的部分杨蛋。


pollQueue方法使用了一個(gè)死循環(huán)(line 182),不斷的去查看queue里面的元素。我們這里重點(diǎn)關(guān)注line 200 -202, 在把隊(duì)列里面的第一個(gè)元素取出之后逞力,我們交給child曙寡,也就是包裝進(jìn)來(lái)的,來(lái)自下一級(jí)的subscriber寇荧,讓它來(lái)執(zhí)行它的onNext()举庶。這樣,我們的原始的Observable的第一個(gè)元素就這樣處理完畢了揩抡。

這整一個(gè)pollQueue方法户侥,因?yàn)楸话b在A(yíng)ction對(duì)象里面,而Action對(duì)象又會(huì)被放進(jìn)Scheduler峦嗤,也就是RxJava包裝過(guò)之后的ExecutorService里面執(zhí)行蕊唐,所以它是會(huì)運(yùn)行在我們指定的那個(gè)線(xiàn)程里面的。我們可以在debug模式下面驗(yàn)證一下烁设。

currentThread已經(jīng)不是安卓的主線(xiàn)程了

所以總結(jié)一下的話(huà)替梨,使用observeOn,會(huì)在原有的Observable發(fā)射元素的時(shí)候,將元素依次添加到一個(gè)隊(duì)列中装黑,并異步的(使用一個(gè)新的線(xiàn)程去執(zhí)行)不停的去獲取隊(duì)列的第一個(gè)元素副瀑,使用下一級(jí)的subscriber處理(onNext())該元素。

簡(jiǎn)單的結(jié)構(gòu)圖


大家可以這樣理解每次發(fā)射新元素的時(shí)候恋谭。糠睡。。

那么我們?cè)賹⑺季S拓展一下疚颊,如果在observeOn后面跟的不是subscribe()方法狈孔,而是一個(gè)map方法。會(huì)有什么不同呢串稀?

如果是map的話(huà)除抛,大家應(yīng)該還記得,下一級(jí)傳上來(lái)的subscriber也不會(huì)是我們?cè)趕ubscribe()方法里面?zhèn)鬟M(jìn)來(lái)的subscriber母截,而是經(jīng)過(guò)OperatorMap改造過(guò)的subscriber了到忽。

OperatorMap的onNext()方法

也就是說(shuō),pollQueue方法的line202清寇,child成員就是OperatorMap改造后的subscriber喘漏,那么執(zhí)行的onNext()也就是上圖line52-58的這個(gè)onNext方法了,line 54中华烟,我們會(huì)在observeOn操作符里面的定義的線(xiàn)程中翩迈,執(zhí)行transformer.call(t),也就是說(shuō),我們保證了map操作符里面的call()方法(就是我們進(jìn)行類(lèi)型轉(zhuǎn)換的方法)是執(zhí)行在observeOn所定義的線(xiàn)程中盔夜,然后在執(zhí)行o.onNext(),這個(gè)o對(duì)象负饲,又是下一級(jí)傳上來(lái)的subscriber堤魁。

所以,假如我們遇到了多次的ObserveOn+Map的轉(zhuǎn)換的話(huà)返十,發(fā)射元素的流程就變成這樣了:

三層observeOn+map的轉(zhuǎn)換

回到我們開(kāi)頭的問(wèn)題妥泉,為什么我們要在原始的Observable發(fā)射元素之間,暫停當(dāng)前線(xiàn)程一秒洞坑?

理由很簡(jiǎn)單盲链,因?yàn)槿绻贿@樣做的話(huà),我們的map轉(zhuǎn)換會(huì)被放到ExectuorService里面執(zhí)行迟杂,是異步執(zhí)行的刽沾,所以很有可能會(huì)出現(xiàn);第一層轉(zhuǎn)換都執(zhí)行完畢排拷,才執(zhí)行下一層轉(zhuǎn)換侧漓,最后日志的打印結(jié)果就不是我們預(yù)測(cè)的那樣了溢豆。

大家想象一下彩库,把上圖的第二和第三層向右方無(wú)限拉長(zhǎng)此衅,拉倒第三map之后哮笆,就會(huì)出現(xiàn)RxJava似乎是在處理完一層之后再處理下一層的錯(cuò)覺(jué)。


那么到此為止阎肝,RxJava進(jìn)階的所有專(zhuān)題都結(jié)束了,其實(shí)關(guān)于RxJava,還有很多東西我們都沒(méi)接觸牛欢,例如怎么handle Subscription等等。這也就留給有興趣的同學(xué)自己慢慢摸索了淆游。接下來(lái)我會(huì)專(zhuān)心準(zhǔn)備Android Tv的教程給大家傍睹。希望有興趣開(kāi)發(fā)安卓TV應(yīng)用的同學(xué)們留意一下 ;)


另外,很高興勇士贏(yíng)球犹菱,作為一個(gè)庫(kù)里球迷拾稳,我忍不住上個(gè)圖:


let's go warriors
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市腊脱,隨后出現(xiàn)的幾起案子访得,更是在濱河造成了極大的恐慌,老刑警劉巖陕凹,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悍抑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杜耙,警方通過(guò)查閱死者的電腦和手機(jī)搜骡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)佑女,“玉大人记靡,你說(shuō)我怎么就攤上這事谈竿。” “怎么了摸吠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵空凸,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蜕便,道長(zhǎng)劫恒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任轿腺,我火速辦了婚禮两嘴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘族壳。我一直安慰自己憔辫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布仿荆。 她就那樣靜靜地躺著贰您,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拢操。 梳的紋絲不亂的頭發(fā)上锦亦,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音令境,去河邊找鬼杠园。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舔庶,可吹牛的內(nèi)容都是我干的抛蚁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惕橙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瞧甩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起弥鹦,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肚逸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后彬坏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吼虎,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年苍鲜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了思灰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡混滔,死狀恐怖洒疚,靈堂內(nèi)的尸體忽然破棺而出歹颓,到底是詐尸還是另有隱情,我是刑警寧澤油湖,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布巍扛,位于F島的核電站,受9級(jí)特大地震影響乏德,放射性物質(zhì)發(fā)生泄漏撤奸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一喊括、第九天 我趴在偏房一處隱蔽的房頂上張望胧瓜。 院中可真熱鬧,春花似錦郑什、人聲如沸府喳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)钝满。三九已至,卻和暖如春申窘,著一層夾襖步出監(jiān)牢的瞬間弯蚜,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工剃法, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熟吏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓玄窝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親悍引。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恩脂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容