作者: @怪盜kidou
如需轉載需在明顯位置保留作者信息及原文鏈接
如果博客中有不恰當之處歡迎留言交流
http://www.lxweimin.com/p/59c3d6bb6a6b
前言
距離上次寫博客又是一個多月了,這次來聊一聊 RxJava 的線程變換,即 observeOn(Scheduler) 和 subscribeOn(Scheduler) 的作用范圍。
為什么要做線程變換
最最簡單的例子就是 Anroid 中數據獲取、處理需要在后臺進行,而展示的過程則需要在UI線程中執行,如果你沒有搞懂 observeOn 和 subscribeOn 的作用范圍,那你以后寫程序的時候 Crash 就會對你不棄不離了,當然了你讀了這篇博客就可以很輕松搞定了!
observeOn
先說結論:observeOn作用于該操作符之后操作符直到出現新的observeOn操作符
舉個例子:
Observable.just("RxJava")
.observeOn(getNamedScheduler("map之前的observeOn"))
.map(s -> {
threadInfo(".map()-1");
return s + "-map1";
})
.map( s -> {
threadInfo(".map()-2");
return s + "-map2";
})
.observeOn(getNamedScheduler("subscribe之前的observeOn"))
.subscribe(s -> {
threadInfo(".onNext()");
System.out.println(s + "-onNext");
});
結果如下:
.map()-1 => map之前的observeOn
.map()-2 => map之前的observeOn
.onNext() => subscribe之前的observeOn
RxJava-map1-map2-onNext
observeOn作用域圖示:
subscribeOn
同樣先說結論:subscribeOn 作用于該操作符之前的 Observable 的創建操符作以及 doOnSubscribe 操作符 ,換句話說就是 doOnSubscribe 以及 Observable 的創建操作符總是被其之后最近的 subscribeOn 控制 。沒看懂不要緊,看下面代碼和圖你就懂了。
舉個例子:
Observable
.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
threadInfo("OnSubscribe.call()");
subscriber.onNext("RxJava");
}
})
.subscribeOn(getNamedScheduler("create之后的subscribeOn"))
.doOnSubscribe(() -> threadInfo(".doOnSubscribe()-1"))
.subscribeOn(getNamedScheduler("doOnSubscribe1之后的subscribeOn"))
.doOnSubscribe(() -> threadInfo(".doOnSubscribe()-2"))
.subscribe(s -> {
threadInfo(".onNext()");
System.out.println(s + "-onNext");
});
結果如下:
.doOnSubscribe()-2 => main
.doOnSubscribe()-1 => doOnSubscribe1之后的subscribeOn
OnSubscribe.call() => create之后的subscribeOn
.onNext() => create之后的subscribeOn
RxJava-onNext
subscribeOn作用域圖示:
3號框中的.doOnSubscribe(() -> threadInfo(".doOnSubscribe()-2"))
的之后由于沒有subscribeOn
操作符所以回調在該段代碼被調用的線程(即主線程)
由于 subscribe 之前 沒有 使用observeOn 指定Scheduler,所以.onNext()
的線程是和OnSubscribe.call()
使用相同的Scheduler 。
其它說明
博文中所謂的 之后、之前 不代表中間沒有其它操作符。
doOnSubscribe
與onStart
類似,均在代碼調用時就會回調,但doOnSubscribe
可以通過subscribeOn
操作符改變運行的線程且越在后面運行越早。
本文中用到的其它方法
public static Scheduler getNamedScheduler(String name) {
return Schedulers.from(Executors.newCachedThreadPool(r -> new Thread(r, name)));
}
public static void threadInfo(String caller) {
System.out.println(caller + " => " + Thread.currentThread().getName());
}
我最近剛剛開通了微信公眾號(怪盜kidou),歡迎關注