RxJava之Scheduler解析(三)

通過(guò)上一篇搞莺,想必大家都對(duì)RxJava有了清楚的認(rèn)識(shí)更哄,那么接下來(lái)我們來(lái)講RxJava的線程控制<code>Schduler</code>邢笙。


一啸如、Scheduler的API

默認(rèn)情況下,RxJava遵循線程不變?cè)瓌t氮惯。即:在哪個(gè)線程調(diào)用subscribe()方法叮雳,就在哪個(gè)線程生產(chǎn)事件,在哪個(gè)線程生產(chǎn)事件妇汗,就在哪個(gè)線程消費(fèi)事件帘不。如果需要切換線程,就需要用到<code>Scheduler</code>(調(diào)度器)杨箭。
  在RxJava中寞焙,<code>Scheduler</code>相當(dāng)于線程控制器,RxJava通過(guò)它來(lái)指定每一段代碼運(yùn)行在什么線程中互婿。RxJava內(nèi)置了幾個(gè)<code>Scheduler</code>捣郊,適合大多數(shù)使用場(chǎng)景:

  • <code> Schedulers.immediate()</code>: 直接在當(dāng)前線程運(yùn)行,相當(dāng)于不指定線程擒悬。這是默認(rèn)的Scheduler模她。
  • <code>Schedulers.newThread()</code>: 總是啟用新線程稻艰,并在新線程執(zhí)行操作懂牧。
  • <code>Schedulers.io()</code>: I/O 操作(讀寫文件、讀寫數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)信息交互等)所使用的Scheduler僧凤。行為模式和newThread()差不多畜侦,區(qū)別在于io()的內(nèi)部實(shí)現(xiàn)是是用一個(gè)無(wú)數(shù)量上限的線程池,可以重用空閑的線程躯保,因此多數(shù)情況下io()比newThread()更有效率旋膳。不要把計(jì)算工作放在io()中,可以避免創(chuàng)建不必要的線程途事。
  • <code>Schedulers.computation()</code>: 計(jì)算所使用的Scheduler验懊。這個(gè)計(jì)算指的是 CPU 密集型計(jì)算,即不會(huì)被 I/O 等操作限制性能的操作尸变,例如圖形的計(jì)算义图。這個(gè)Scheduler使用的固定的線程池,大小為 CPU 核數(shù)召烂。不要把 I/O 操作放在computation()中碱工,否則 I/O 操作的等待時(shí)間會(huì)浪費(fèi) CPU。
  • Android 專用的<code>AndroidSchedulers.mainThread()</code>奏夫,它指定的操作將在 Android 主線程運(yùn)行怕篷。

有了這幾個(gè) <code>Scheduler</code> ,就可以使用 subscribeOn()和 observeOn()兩個(gè)方法來(lái)對(duì)線程進(jìn)行控制了酗昼。

<code>subscribeOn()</code>:* 指定subscribe()(訂閱/注冊(cè))所發(fā)生的線程廊谓,即 Observable.OnSubscribe被激活時(shí)所處的線程÷橄鳎或者叫做事件產(chǎn)生的線程蹂析。*

<code>observeOn()</code>: 指定Subscriber(觀察者)所運(yùn)行在的線程〉牛或者叫做事件消費(fèi)的線程电抚。

文字?jǐn)⑹隹倸w難理解,上代碼:

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程(即 Action1對(duì)象)
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

上面這段代碼中竖共,由于 <code>subscribeOn(Schedulers.io())</code>的指定蝙叛,被創(chuàng)建的事件的內(nèi)容 1、2公给、3借帘、4將會(huì)在 IO 線程發(fā)出;而由于<code>observeOn(AndroidScheculers.mainThread())</code> 的指定淌铐,因此 subscriber數(shù)字的打印將發(fā)生在主線程 肺然。事實(shí)上,這種在subscribe()之前寫上兩句 <code>subscribeOn(Scheduler.io())</code>和 <code>observeOn(AndroidSchedulers.mainThread())</code>的使用方式非常常見(jiàn)腿准,它適用于多數(shù)的 『后臺(tái)線程取數(shù)據(jù)际起,主線程顯示』的程序策略拾碌。
  前面講到了,可以利用 subscribeOn()結(jié)合 observeOn()來(lái)實(shí)現(xiàn)線程控制街望,讓事件的產(chǎn)生和消費(fèi)發(fā)生在不同的線程校翔。那么可以多切換幾次線程嗎?那你就要了解RxJava變換的原理了灾前。

二防症、Scheduler的原理

其實(shí), subscribeOn() 和 observeOn()的內(nèi)部實(shí)現(xiàn)哎甲,也是用的 lift()蔫敲。具體看圖(不同顏色的箭頭表示不同的線程):
  <code>subscribeOn()</code>原理圖:

Paste_Image.png

<code>observeOn()</code>原理圖:

Paste_Image.png

  從圖中可以看出,<code>subscribeOn()</code> 和 <code>observeOn()</code>都做了線程切換的工作(圖中的 "schedule..." 部位)炭玫。不同的是燕偶, <code>subscribeOn()</code>的線程切換發(fā)生在 OnSubscribe中,即在它通知上一級(jí) OnSubscribe時(shí)础嫡,這時(shí)事件還沒(méi)有開(kāi)始發(fā)送指么,因此 <code>subscribeOn()</code>的線程控制可以從事件發(fā)出的開(kāi)端就造成影響;而 <code>observeOn()</code>的線程切換則發(fā)生在它內(nèi)建的 Subscriber中榴鼎,即發(fā)生在它即將給下一級(jí)Subscriber 發(fā)送事件時(shí)伯诬,因此 <code>observeOn()</code>控制的是它后面的線程。
  最后巫财,我用一張圖來(lái)解釋當(dāng)多個(gè) <code>subscribeOn()</code>和 <code>observeOn()</code>混合使用時(shí)盗似,線程調(diào)度是怎么發(fā)生的(由于圖中對(duì)象較多,相對(duì)于上面的圖對(duì)結(jié)構(gòu)做了一些簡(jiǎn)化調(diào)整):

Paste_Image.png

  圖中共有 5 處含有對(duì)事件的操作平项。由圖中可以看出赫舒,①和②兩處受第一個(gè) <code>subscribeOn()</code>影響,運(yùn)行在紅色線程闽瓢;③和④處受第一個(gè)<code>observeOn()</code>的影響接癌,運(yùn)行在綠色線程;⑤處受第二個(gè) <code>onserveOn()</code>影響扣讼,運(yùn)行在紫色線程缺猛;而第二個(gè) <code>subscribeOn()</code>,由于在通知過(guò)程中線程就被第一個(gè) <code>subscribeOn()</code>
截?cái)嗤址虼藢?duì)整個(gè)流程并沒(méi)有任何影響荔燎。這里也就回答了前面的問(wèn)題:當(dāng)使用了多個(gè)<code>subscribeOn()</code>的時(shí)候,只有第一個(gè) <code>subscribeOn()</code>起作用销钝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末有咨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒸健,更是在濱河造成了極大的恐慌座享,老刑警劉巖婉商,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異征讲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)橡娄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門诗箍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人挽唉,你說(shuō)我怎么就攤上這事滤祖。” “怎么了瓶籽?”我有些...
    開(kāi)封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵匠童,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我塑顺,道長(zhǎng)汤求,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任严拒,我火速辦了婚禮扬绪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裤唠。我一直安慰自己挤牛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布种蘸。 她就那樣靜靜地躺著墓赴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪航瞭。 梳的紋絲不亂的頭發(fā)上诫硕,一...
    開(kāi)封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音刊侯,去河邊找鬼痘括。 笑死,一個(gè)胖子當(dāng)著我的面吹牛滔吠,可吹牛的內(nèi)容都是我干的纲菌。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼疮绷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼翰舌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起冬骚,我...
    開(kāi)封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤椅贱,失蹤者是張志新(化名)和其女友劉穎懂算,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體庇麦,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡计技,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了山橄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垮媒。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖航棱,靈堂內(nèi)的尸體忽然破棺而出睡雇,到底是詐尸還是另有隱情,我是刑警寧澤饮醇,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布它抱,位于F島的核電站,受9級(jí)特大地震影響朴艰,放射性物質(zhì)發(fā)生泄漏观蓄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一祠墅、第九天 我趴在偏房一處隱蔽的房頂上張望蜘腌。 院中可真熱鬧,春花似錦饵隙、人聲如沸撮珠。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)芯急。三九已至,卻和暖如春驶俊,著一層夾襖步出監(jiān)牢的瞬間娶耍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工饼酿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榕酒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓故俐,卻偏偏與公主長(zhǎng)得像想鹰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子药版,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

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