RxJava學習筆記4

這裏我們再來深入學習一下RxJava的線程調度,在RxJava學習筆記2中簡單對RxJava中的線程調度進行了簡單的使用介紹,這裏我麼繼續深入線程調度在RxJava中的提現

可以利用 subscribeOn() 結合 observeOn() 來實現線程控制,讓事件的產生和消費發生在不同的線程。可是在瞭解了 map() flatMap() 等變換方法後,內部出現了不少的Obserable,自然會多出了不少的發送事件和消費事件,那麼能不能多切換幾次線程?

回答是肯定的。因爲 observeOn() 指定的是 Subscriber 消費的線程,而這個 Subscriber 並不是(嚴格說應該爲『不一定是』,但這裏不妨理解爲『不是』)subscribe() 參數中的 Subscriber ,

而是 observeOn() 執行時的當前 Observable 所對應的 Subscriber ,即它的直接下級 Subscriber

換句話說,observeOn() 指定的是它之後的操作所在的線程。因此如果有多次切換線程的需求,只要在每個想要切換線程的位置調用一次 observeOn() 即可。上代碼:

Observable.just(1, 2, 3, 4) // IO 線程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io()) //指定 解析 1234的發生線程

    .observeOn(Schedulers.newThread()) //指定直接下級的直接線程
    .map(mapOperator) // 新線程,由 observeOn() 指定 

    .observeOn(Schedulers.io())  //直接指定下級的直接線程
    .map(mapOperator2) // IO 線程,由 observeOn() 指定

    .observeOn(AndroidSchedulers.mainThread) //直接指定下級的直接線程


和observeOn()相比較 ,
 subscribeOn() 的位置放在哪裏都可以,但它是隻能調用一次的。

這裏寫圖片描述

圖中的 schedule…就是線程調度的地方

subscribeOn() 的線程切換髮生在 OnSubscribe 中,即在它通知上一級 OnSubscribe 時,這時事件還沒有開始發送,因此 subscribeOn() 的線程控制可以從事件發出的開端就造成影響;

observeOn() 的線程切換則發生在它內建的 Subscriber 中,即發生在它即將給下一級 Subscriber 發送事件時,因此 observeOn() 控制的是它後面的線程。

我們再回過頭 看一眼 多次 執行subscribeOn()會有什麼後果。

這裏寫圖片描述

圖中共有 5 處含有對事件的操作。由圖中可以看出,
①和②兩處受第一個 subscribeOn() 影響,運行在紅色線程;
③和④處受第一個 observeOn() 的影響,運行在綠色線程;
⑤處受第二個 onserveOn() 影響,運行在紫色線程;

而第二個 subscribeOn() ,由於在通知過程中線程就被第一個 subscribeOn() 截斷,因此對整個流程並沒有任何影響。這裏也就回答了前面的問題:當使用了多個 subscribeOn() 的時候,只有第一個 subscribeOn() 起作用。


延伸:doOnSubscribe()

然而,雖然超過一個的 subscribeOn() 對事件處理的流程沒有影響,但在流程之前卻是可以利用的。

在前面講 Subscriber 的時候,提到過 Subscriber 的 onStart() 可以用作流程開始前的初始化。然而 onStart() 由於在 subscribe() 發生時就被調用了,因此不能指定線程,而是隻能執行在 subscribe() 被調用時的線程。這就導致如果 onStart() 中含有對線程有要求的代碼(例如在界面上顯示一個 ProgressBar,這必須在主線程執行),將會有線程非法的風險,因爲有時你無法預測 subscribe() 將會在什麼線程執行。

而與 Subscriber.onStart() 相對應的,有一個方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同樣是在 subscribe() 調用後而且在事件發送前執行,但區別在於它可以指定線程
默認情況下, doOnSubscribe() 執行在 subscribe() 發生的線程;
如果在 doOnSubscribe() 之後有 subscribeOn() 的話,它將執行在離它最近的 subscribeOn() 所指定的線程

Observable.create(onSubscribe)
    .subscribeOn(Schedulers.io())
    .doOnSubscribe(new Action0() {
        public void call() {
            progressBar.setVisibility(View.VISIBLE); // 需要在主線程執行
        }
    })
    .subscribeOn(AndroidSchedulers.mainThread()) 
    // 指定主線程 >>通過在這裏指定 使得 上面一段代碼的線程可以發生在主線程中 >>>>這是個實用的技巧 請記住 
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(subscriber);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章