1. 程式人生 > >RXJava——執行緒控制 —— Scheduler (一)

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
    。這個計算指的是 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(newAction1<Integer>(){@Overridepublicvoid call(Integer number){Log.d(tag,"number:"+ number);}});

上面這段程式碼中,由於 subscribeOn(Schedulers.io()) 的指定,被建立的事件的內容 1234 將會在 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 的原理需要放在後面講,因為它的原理是以下一節《變換》的原理作為基礎的。

好吧這一節其實我屁也沒說,只是為了讓你安心,讓你知道我不是忘了講原理,而是把它放在了更合適的地方。