RxJava線程切換——ObserveOn和SubscribeOn的區(qū)別

RxJava很優(yōu)勢的一個方面就是他的線程切換精绎,基本是依靠ObserveOn和SubscribeOn這兩個操作符來完成的友鼻。

先來看看什么是ObserveOn和SubscribeOn,官方對他們的定義是這樣的:

  • ObserveOn

specify the Scheduler on which an observer will observe this Observable
指定一個觀察者在哪個調(diào)度器上觀察這個Observable

  • SubscribeOn

specify the Scheduler on which an Observable will operate
指定Observable自身在哪個調(diào)度器上執(zhí)行

官方的圖例

By default, an Observable and the chain of operators that you apply to it will do its work, and will notify its observers, on the same thread on which its Subscribe method is called. The SubscribeOn operator changes this behavior by specifying a different Scheduler on which the Observable should operate. The ObserveOn operator specifies a different Scheduler that the Observable will use to send notifications to its observers.

As shown in this illustration, the SubscribeOn operator designates which thread the Observable will begin operating on, no matter at what point in the chain of operators that operator is called. ObserveOn, on the other hand, affects the thread that the Observable will use below where that operator appears. For this reason, you may call ObserveOn multiple times at various points during the chain of Observable operators in order to change on which threads certain of those operators operate.

從上面的圖例中可以看出知染,SubscribeOn這個操作符指定的是Observable自身在哪個調(diào)度器上執(zhí)行寺枉,而且跟調(diào)用的位置沒有關(guān)系。而ObservableOn則是指定一個觀察者在哪個調(diào)度器上觀察這個Observable幻件,當每次調(diào)用了ObservableOn這個操作符時,之后都會在選擇的調(diào)度器上進行觀察蛔溃,直到再次調(diào)用ObservableOn切換了調(diào)度器绰沥。
那么,如果多次調(diào)用SubscribeOn贺待,會有什么效果呢徽曲?寫個例子測試一下就知道了。

      Observable.just(1)
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-1:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .subscribeOn(Schedulers.newThread())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-2:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .subscribeOn(Schedulers.io())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-3:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "subscribe:"+Thread.currentThread().getName());
                    }
                });

在例子用麸塞,我多次調(diào)用了subscribeOn操作符秃臣,并且在每個map操作符中打印了當前線程的名稱。


多次調(diào)用SubscribeOn

從打印的日志中可以看出哪工,只有第一次調(diào)用SubscribeOn時選擇的調(diào)度器.subscribeOn(Schedulers.newThread())有作用奥此,而后來選擇的都沒有作用。這說明了SubscribeOn這個操作符雁比,與調(diào)用的位置無關(guān)稚虎,而且只有第一次調(diào)用時會指定Observable自己在哪個調(diào)度器執(zhí)行。

其實有一種情況特殊偎捎,就是在DoOnSubscribe操作符之后調(diào)用蠢终,可以使DoOnSubscribe在指定的調(diào)度器中執(zhí)行。

        Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> observableEmitter) throws Exception {
                Log.i(TAG, "create:" + Thread.currentThread().getName());
                observableEmitter.onNext(1);
                observableEmitter.onComplete();
            }
        });
        observable.subscribeOn(Schedulers.newThread())
                .observeOn(Schedulers.io())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map:" + Thread.currentThread().getName());
                        return integer;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(@NonNull Disposable disposable) throws Exception {
                        Log.i(TAG, "doOnSubscribe:" + Thread.currentThread().getName());
                    }
                })
                .subscribeOn(Schedulers.io())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "subscribe:" + Thread.currentThread().getName());
                    }
                });
切換DoOnSubscribe調(diào)度器

由此可見茴她,SubscribeOn不僅可以指定Observable自身的調(diào)度器寻拂,也可以指定DoOnSubscribe執(zhí)行的調(diào)度器。

我們知道了多次調(diào)用SubscribeOn并不會起作用丈牢,那么多次調(diào)用ObservableOn呢祭钉?還是同樣的例子,將所有SubscribeOn換為ObservableOn試試赡麦。

      Observable.just(1)
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-1:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .observeOn(Schedulers.newThread())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-2:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .observeOn(Schedulers.io())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "map-3:"+Thread.currentThread().getName());
                        return integer;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.i(TAG, "subscribe:"+Thread.currentThread().getName());
                    }
                });

從打印的日志中可以看出朴皆,每次調(diào)用了ObservableOn操作符之后,之后的Map和Subscribe操作符都會發(fā)生在指定的調(diào)度器中泛粹,實現(xiàn)了線程的切換遂铡。


多次調(diào)用ObservableOn

平時我們見到最多的使用場景,可能就是官方圖例上描述的那樣晶姊,配合Retrofit從網(wǎng)絡(luò)拿回數(shù)據(jù)扒接、在io線程或子線程執(zhí)行某些耗時操作,比如一些變換操作,然后再切換到主線程去更新UI钾怔,可以用RxJava的線程切換很方便的實現(xiàn)碱呼。但是這只是很簡單的應(yīng)用場景之一,RxJava能做的遠不止這些宗侦,我仍在不斷的摸索中愚臀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矾利,隨后出現(xiàn)的幾起案子姑裂,更是在濱河造成了極大的恐慌,老刑警劉巖男旗,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舶斧,死亡現(xiàn)場離奇詭異,居然都是意外死亡察皇,警方通過查閱死者的電腦和手機茴厉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來什荣,“玉大人矾缓,你說我怎么就攤上這事±6茫” “怎么了而账?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長因篇。 經(jīng)常有香客問我,道長笔横,這世上最難降的妖魔是什么竞滓? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吹缔,結(jié)果婚禮上商佑,老公的妹妹穿的比我還像新娘。我一直安慰自己厢塘,他們只是感情好茶没,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晚碾,像睡著了一般抓半。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上格嘁,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天笛求,我揣著相機與錄音,去河邊找鬼。 笑死探入,一個胖子當著我的面吹牛狡孔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜂嗽,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼苗膝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了植旧?” 一聲冷哼從身側(cè)響起辱揭,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隆嗅,沒想到半個月后界阁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡胖喳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年泡躯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丽焊。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡较剃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出技健,到底是詐尸還是另有隱情写穴,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布雌贱,位于F島的核電站啊送,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏欣孤。R本人自食惡果不足惜馋没,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望降传。 院中可真熱鬧篷朵,春花似錦、人聲如沸婆排。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽段只。三九已至腮猖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翼悴,已是汗流浹背缚够。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工幔妨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谍椅。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓误堡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雏吭。 傳聞我的和親對象是個殘疾皇子锁施,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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