RXJava——執行緒控制 —— Scheduler (一)
原文連結:http://gank.io/post/560e15be2dca930e00da1083
在不指定執行緒的情況下, RxJava 遵循的是執行緒不變的原則,即:在哪個執行緒呼叫 subscribe()
,就在哪個執行緒生產事件;在哪個執行緒生產事件,就在哪個執行緒消費事件。如果需要切換執行緒,就需要用到
Scheduler
(排程器)。
1) Scheduler 的 API (一)
在RxJava 中,Scheduler
——排程器,相當於執行緒控制器,RxJava 通過它來指定每一段程式碼應該執行在什麼樣的執行緒。RxJava 已經內建了幾個
Scheduler
,它們已經適合大多數的使用場景:
Schedulers.immediate()
Scheduler
。Schedulers.newThread()
: 總是啟用新執行緒,並在新執行緒執行操作。Schedulers.io()
: I/O 操作(讀寫檔案、讀寫資料庫、網路資訊互動等)所使用的Scheduler
。行為模式和newThread()
差不多,區別在於io()
的內部實現是是用一個無數量上限的執行緒池,可以重用空閒的執行緒,因此多數情況下io()
比newThread()
更有效率。不要把計算工作放在io()
中,可以避免建立不必要的執行緒。Schedulers.computation()
: 計算所使用的Scheduler
Scheduler
使用的固定的執行緒池,大小為 CPU 核數。不要把 I/O 操作放在computation()
中,否則 I/O 操作的等待時間會浪費 CPU。- 另外, Android 還有一個專用的
AndroidSchedulers.mainThread()
,它指定的操作將在 Android 主執行緒執行。
有了這幾個 Scheduler
,就可以使用 subscribeOn()
和 observeOn()
兩個方法來對執行緒進行控制了。*
subscribeOn()
: 指定 subscribe()
Observable.OnSubscribe
被啟用時所處的執行緒。或者叫做事件產生的執行緒。*
observeOn()
: 指定 Subscriber
所執行在的執行緒。或者叫做事件消費的執行緒。
文字敘述總歸難理解,上程式碼:
Observable.just(1,2,3,4).subscribeOn(Schedulers.io())// 指定 subscribe() 發生在 IO 執行緒.observeOn(AndroidSchedulers.mainThread())// 指定 Subscriber 的回調發生在主執行緒.subscribe(newAction1<Integer>(){@Overridepublicvoid call(Integer number){Log.d(tag,"number:"+ number);}});
上面這段程式碼中,由於 subscribeOn(Schedulers.io())
的指定,被建立的事件的內容 1
、2
、3
、4
將會在 IO 執行緒發出;而由於
observeOn(AndroidScheculers.mainThread()
) 的指定,因此 subscriber
數字的列印將發生在主執行緒 。事實上,這種在
subscribe()
之前寫上兩句 subscribeOn(Scheduler.io())
和
observeOn(AndroidSchedulers.mainThread())
的使用方式非常常見,它適用於多數的 『後臺執行緒取資料,主執行緒顯示』的程式策略。
而前面提到的由圖片 id 取得圖片並顯示的例子,如果也加上這兩句:
int drawableRes =...;ImageView imageView =...;Observable.create(newOnSubscribe<Drawable>(){@Overridepublicvoid call(Subscriber<?superDrawable> subscriber){Drawable drawable = getTheme().getDrawable(drawableRes));
subscriber.onNext(drawable);
subscriber.onCompleted();}}).subscribeOn(Schedulers.io())// 指定 subscribe() 發生在 IO 執行緒.observeOn(AndroidSchedulers.mainThread())// 指定 Subscriber 的回調發生在主執行緒.subscribe(newObserver<Drawable>(){@Overridepublicvoid onNext(Drawable drawable){
imageView.setImageDrawable(drawable);}@Overridepublicvoid onCompleted(){}@Overridepublicvoid onError(Throwable e){Toast.makeText(activity,"Error!",Toast.LENGTH_SHORT).show();}});
那麼,載入圖片將會發生在 IO 執行緒,而設定圖片則被設定在了主執行緒。這就意味著,即使載入圖片耗費了幾十甚至幾百毫秒的時間,也不會造成絲毫介面的卡頓。
2) Scheduler 的原理 (一)
RxJava 的 Scheduler API 很方便,也很神奇(加了一句話就把執行緒切換了,怎麼做到的?而且 subscribe()
不是最外層直接呼叫的方法嗎,它竟然也能被指定執行緒?)。然而 Scheduler 的原理需要放在後面講,因為它的原理是以下一節《變換》的原理作為基礎的。
好吧這一節其實我屁也沒說,只是為了讓你安心,讓你知道我不是忘了講原理,而是把它放在了更合適的地方。