徹底搞懂 RxJava — 高階篇

yangxi_001發表於2017-05-17

前言

本文獻給所有想要深入瞭解 RxJava 的人.

如果你還沒閱讀過基礎部分, 請先補習一下功課. 此外, 強烈建議你徹底理解中級部分再來閱讀本文.

本文將帶你理解 `.subscribeOn(Schedulers.io())` 和 `.observeOn(Schedulers.computation())` 用法背後的原理.

先看一下基本使用

1

我們來拆解一下 `.subscribeOn` 和 `.observeOn` 的作用範圍:

2

  • `subscribeOn` 將作用於 `create` 中的 `OnSubscribe.call()` 方法.
  • `observeOn` 作用於其語法中下一語句的 `Subscriber.onNext` 等函式中.

原始碼分析

首先分析 `subscribeOn`

untitled

中級篇中的 `map` 一樣, 是通過建立了一個 `Observable` 來轉發 `OnSubscribe.call` 請求(程式碼中的 `OperatorSubscribeOn` 繼承自 `OnSubscribe`). 來看看具體實現(已略去無關程式碼):

1
2
3
4
5
6
7
8
9
public void call(final Subscriber<? super T> subscriber) {
   final Worker inner = scheduler.createWorker();
   inner.schedule(new Action0() {
      @Override
      public void call() {
         source.unsafeSubscribe(s);
      }
   });
}

可見, 該函式中做了如下兩件事:

  1. 建立一個用於在不同執行緒執行的 `Worker` 物件(程式碼中的 inner)
  2. 使用上述 `inner` 在該物件所代表的執行緒中執行 `Observable.onSubscribe.call` 方法(程式碼中的 `source.unsafeSubscribe(s);`

梳理一下 `SUBSCRIBEON` 的實現方法

再來分析稍微複雜一點兒的 `observeOn`

k

回顧一下 `LIFT`

1
2
3
4
5
6
7
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
   return new Observable<R>(new OnSubscribe<R>() {
      public void call(Subscriber<? super R> o) {
         Subscriber<? super T> st = hook.onLift(operator).call(o);onSubscribe.call(st);
      }
   });
}

`lift` 建立建立了一個 `Observable` 和 一個 `OnSubscriber` 物件. 而在 `OnSubscribe` 物件中又建立了一個 `Subscriber` (程式碼中的 `st`) 物件. 整個 `observeOn` 的重點也就在這個 `st` 物件中. 我們先來看一下 `st` 是如何生成的:

`hook.onLift(operator).call(o);` 實際上呼叫的就是 `operator.call(o)`. 而 `operator` 是 `OperatorObserveOn` 的例項. 所以看下 `OperatorObserveOn.call` 方法是如何生成 `st` 物件的(已略去無關程式碼):

1
2
3
4
5
6
7
8
9
10
11
12
13
public Subscriber<? super T> call(Subscriber<? super T> child) {
   if (scheduler instanceof ImmediateScheduler) {
      // avoid overhead, execute directly
      return child;
   } else if (scheduler instanceof TrampolineScheduler) {
      // avoid overhead, execute directly
      return child;
   } else {
      ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError);
      parent.init();
      return parent;
   }
}

該方法會根據 `scheduler` 的型別決定使用什麼方式返回 `Subscriber` 物件. 可見, 如果 child 型別為 `ImmediateScheduler` 或者 `TrampolineScheduler` 等以當前執行緒為執行環境的型別, 則直接返回 `child` 物件. 本例中, `child` 為 `NewThreadScheduler`, 因此將通過 `ObserveOnSubscriber` 對 `child` 進行包裝. 生成一個 proxy subscriber 物件.

至此, 我們可以知道 `observeOn` 是通過以下方法對其後面的 `Subscriber` 進行控制的:

  1.  `lift` -> `OnSubscribe.call`  ->  `proxy subscriber = new Subscriber(original subscriber)` 建立了一個新的 `Subscriber`(實際上是個代理)
  2. 在上述 `proxy subscriber` 中對 `original subscriber` 物件的執行進行轉發. 轉發過程中, `proxy subscriber` 完全可以自由的控制 `original subscriber` 執行的執行緒.

整體梳理一下 `subscribeOn` + `observeOn` 的實現方法

Refs:

Grokking 帶你入門
Grokking RxJava, Part 1: The Basics
Grokking RxJava, Part 2: Operator, Operator
Grokking RxJava, Part 3: Reactive with Benefits
Grokking RxJava, Part 4: Reactive Android

Bruce 大頭鬼
RxJava基本流程和lift原始碼分析

扔物線大神
給 Android 開發者的 RxJava 詳解

讀原始碼!
ReactiveX/RxJava

walfud 徹底搞懂 RxJava 系列
徹底搞懂 RxJava — 初級篇
徹底搞懂 RxJava — 中級篇
徹底搞懂 RxJava — 高階篇

學以致用:
FlowImageLoader — 基於 RxJava 實現的圖片非同步載入庫. 該庫作者即 ‘徹底搞懂 RxJava 系列` 作者

Rx 規範
ReactiveX — An API for asynchronous programming  (其中最有用的是 Contract)

其它
Awesome-RxJava
RxJava Essential CN (幫助你瞭解各種 Operator 的使用)

相關文章