Android 開發者的 RxJava 詳解(三)
3.執行緒控制 —— Scheduler (一)
在不指定執行緒的情況下, RxJava 遵循的是執行緒不變的原則,即:在哪個執行緒呼叫 subscribe(),就在哪個執行緒生產事件;在哪個執行緒生產事件,就在哪個執行緒消費事件。如果需要切換執行緒,就需要用到 Scheduler (排程器)。
3.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
。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個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(new Action1<Integer>() { @Override public void 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(new OnSubscribe<Drawable>() { @Override public void call(Subscriber<? super Drawable> subscriber) { Drawable drawable = getTheme().getDrawable(drawableRes)); subscriber.onNext(drawable); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 執行緒 .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主執行緒 .subscribe(new Observer<Drawable>() { @Override public void onNext(Drawable drawable) { imageView.setImageDrawable(drawable); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show(); } });
那麼,載入圖片將會發生在 IO 執行緒,而設定圖片則被設定在了主執行緒。這就意味著,即使載入圖片耗費了幾十甚至幾百毫秒的時間,也不會造成絲毫介面的卡頓。
3.2 Scheduler 的原理 (一)
RxJava 的 Scheduler API 很方便,也很神奇(加了一句話就把執行緒切換了,怎麼做到的?而且 subscribe() 不是最外層直接呼叫的方法嗎,它竟然也能被指定執行緒?)。然而 Scheduler 的原理需要放在後面講,因為它的原理是以下一節《變換》的原理作為基礎的。
好吧這一節其實我屁也沒說,只是為了讓你安心,讓你知道我不是忘了講原理,而是把它放在了更合適的地方。
【附錄】

資料圖
需要資料的朋友可以加入Android架構交流QQ群聊:513088520
點選連結加入群聊【Android移動架構總群】: 加入群聊
獲取免費學習視訊,學習大綱另外還有像高階UI、效能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)等Android高階開發資料免費分享。