轉載請標明地址 QuincySx:[www.jianshu.com/p/a9ebf730c… ]
讀了這篇文章你將會收穫什麼
- RxJava2 基本的執行流程(並不會詳述)
- RxJava2 執行緒切換原理
- 為什麼 subscribeOn() 只有第一次切換有效
- RxAndroid 簡單分析
PS:建議您對 RxJava 有一些瞭解或使用經驗再看此文章,推薦結合原始碼品嚐 RxJava入門文章 [給 Android 開發者的 RxJava 詳解-扔物線(gank.io/post/560e15…)
然後貼一下本篇文章分析的示例程式碼
CompositeDisposable comDisposable = new CompositeDisposable();
protected void test() {
Observable<String> observable = Observable
.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull ObservableEmitter<String> emitter) throws
Exception {
emitter.onNext("hello");
}
})
.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
return s;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
comDisposable.add(d);
}
@Override
public void onNext(String s) {
Log.i(TAG, s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
複製程式碼
RxJava2 基本的執行流程
根據上述原始碼分析出流程圖,這裡顏色相同的代表同一物件。根據流程圖看一遍原始碼基本流程就能理通

RxJava2 執行緒切換原理
RxJava 切換執行緒怎麼用我就不多說了請參考我的另一篇文章 Android:隨筆——RxJava的執行緒切換
一、observeOn() 的執行緒切換原理
根據執行流程來看 observeOn() 執行後是得到 ObservableObserveOn 物件,那麼當 ObservableObserveOn 繫結監聽者的時候要執行 subscribe() 方法
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
//呼叫 subscribeActual()
subscribeActual(observer);
} catch (NullPointerException e) { // NOPMD
throw e;
} catch (Throwable e) {
...
}
}
複製程式碼
接下來我們看一下 subscribeActual() 方法
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
//scheduler 是傳進來的執行緒排程物件,如 Schedulers.io() 、AndroidSchedulers.mainThread() 等,這裡呼叫了 createWorker() 方法暫時看一下就好稍後分析 RxAndroid 會說明
Scheduler.Worker w = scheduler.createWorker();
//我們看到他把 w 引數傳進去了
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
複製程式碼
從上述程式碼我們可以看到 ObservableObserveOn 是被 ObserveOnObserver 監聽的,所以收到通知也是由 ObserveOnObserver 作出響應,接下來我們假設當 Rxjava 傳送 onNext 通知時會呼叫 ObserveOnObserver 的 onNext() 方法 ( PS:當然如果是 onComplete()、onError() 等也是一樣的邏輯 ),然後我們來看一看 ObserveOnObserver 的 onNext() 方法,
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
//切換執行緒
schedule();
}
void schedule() {
if (getAndIncrement() == 0) {
//直接呼叫了 worker 的 schedule 方法,需要注意的是這裡他把自己傳了進去
worker.schedule(this);
}
}
複製程式碼
現在我先把把 schedule(Runnable run) 貼出來
public Disposable schedule(@NonNull Runnable run) {
return schedule(run, 0L, TimeUnit.NANOSECONDS);
}
複製程式碼
- 我們看到這個他接收的引數是一個 Runnable,這是怎麼回事呢,我們看一下 ObserveOnObserver 物件,他不但實現了 Observer 介面並且也實現了 Runnable 介面
- 接下看,繼續呼叫 schedule( Runnable action, long delayTime, TimeUnit unit) 方法,但是這個方法是個抽象方法,這裡我們就假設這裡這個 worker 是 IO 執行緒,所以我直接貼 IoScheduler 的程式碼了
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
複製程式碼
然後再貼一下 scheduleActual 的方法
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//就是個 Runnable
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}
Future<?> f;
try {
//判斷延遲時間,然後使用執行緒池執行 Runnable
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);
} else {
f = executor.schedule((Callable<Object>)sr, delayTime, unit);
}
sr.setFuture(f);
} catch (RejectedExecutionException ex) {
if (parent != null) {
parent.remove(sr);
}
RxJavaPlugins.onError(ex);
}
return sr;
}
複製程式碼
這樣一來就會在相應的執行緒中執行 ObserveOnObserver 的 run 方法
public void run() {
//這個地方具體的我還沒有搞明白,大概就是在這個方法裡呼叫 onNext() ,然後 observeOn() 操作符之後的監聽者的執行執行緒就變了
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
複製程式碼
二、subscribeOn() 的執行緒切換原理
PS:這個切換原理其實和 observeOn() 原理很像
跟 observeOn() 一樣,只不過這個操作的物件是 ObservableSubscribeOn, 這個物件也是同樣的程式碼邏輯,執行 subscribe() 方法,然後呼叫 subscribeActual() 方法,所以就直接貼 subscribeActual() 的程式碼
public void subscribeActual(final Observer<? super T> s) {
//建立與之繫結的 SubscribeOnObserver
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
//1. 建立 SubscribeTask 實際上就是個 Runnable
//2. 然後呼叫 scheduler.scheduleDirect 方法
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
複製程式碼
我們看一下 scheduleDirect 的方法
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//一個 Runnable 具體作用沒分析
DisposeTask task = new DisposeTask(decoratedRun, w);
//這個程式碼看著熟悉嗎 沒錯上面 observeOn 提到過,知道它是執行 Runnable 我們就直接看 Runnable 裡面的 run() 了
w.schedule(task, delay, unit);
return task;
}
複製程式碼
我們看一下 DisposeTask 的 run()
public void run() {
runner = Thread.currentThread();
try {
decoratedRun.run();
} finally {
dispose();
runner = null;
}
}
複製程式碼
調來調去我們又回到了 SubscribeTask 的 run()
public void run() {
source.subscribe(parent);
}
複製程式碼
這個地方的執行執行緒已經被切換了,他又開始往上一層層的去訂閱,所以 create(new ObservableOnSubscribe(){})這個匿名實現介面執行 subscribe 的執行緒執行環境都被改變了,再去呼叫 onNext() 等方法執行緒環境也是被改變的
為什麼 subscribeOn() 只有第一次切換有效
寫到這裡我們這個問題也就能回答了 因為 RxJava 最終能影響 ObservableOnSubscribe 這個匿名實現介面的執行環境的只能是最後一次執行的 subscribeOn() ,又因為 RxJava 訂閱的時候是從下往上訂閱,所以從上往下第一個 subscribeOn() 就是最後執行的,這就造成了寫多個 subscribeOn() 並沒有什麼亂用的現象。
分析一下 RxAndroid

其實它的原理和 RxJava 自帶的那些執行緒排程器一樣,如果你想了解 RxJava 的 IO 執行緒池,什麼的可以自己看一看,我這裡分析 RxAndroid 主要有以下幾點原因
- 弄清楚 RxAndroid 這個庫的具體作用
- 弄清楚他是怎麼就能把執行緒切換到主執行緒(他是怎麼提供的主執行緒環境)
- 弄清楚執行緒排程器的執行原理
- 最重要的是它相對於 RxJava 自帶的那些排程器,他比較簡單容易分析
正文開始
首先我們找一下入口 AndroidSchedulers.mainThread() 這個地方應該是就是入口了,我們看一下 AndroidSchedulers 這個類的原始碼吧,總共也沒幾行
private static final class MainHolder {
static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
}
private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
new Callable<Scheduler>() {
@Override public Scheduler call() throws Exception {
return MainHolder.DEFAULT;
}
}
);
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
public static Scheduler from(Looper looper) {
if (looper == null) throw new NullPointerException("looper == null");
return new HandlerScheduler(new Handler(looper));
}
複製程式碼
這個應該不用我多說大家都能看明白,看到這裡我們基本上明白了 RxAndroid 就是通過 Handler 來拿到主執行緒的
我們拿 subscribeOn() 中的一些流程來說
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
DisposeTask task = new DisposeTask(decoratedRun, w);
w.schedule(task, delay, unit);
return task;
}
複製程式碼
首先我們看到呼叫了 createWorker() 這是個抽象方法我們找到具體實現類 HandlerScheduler
public Worker createWorker() {
return new HandlerWorker(handler);
}
複製程式碼
單純的建立一個 Worker 並把主執行緒的 Handler 傳進去,然後呼叫 Worker 的 schedule() 方法
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
/**忽略一些程式碼**/
run = RxJavaPlugins.onSchedule(run);
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
Message message = Message.obtain(handler, scheduled);
message.obj = this; // Used as token for batch disposal of this worker's runnables.
handler.sendMessageDelayed(message, unit.toMillis(delay));
if (disposed) {
handler.removeCallbacks(scheduled);
return Disposables.disposed();
}
return scheduled;
}
複製程式碼
到這裡看明白 RxJava 如何通過 RxAndroid 來切換到主執行緒執行,其實 RxAndroid 的核心就是 Handler
總結
本篇參考 RxJava 2.1.12 與 RxAndroid:2.0.2 原始碼 不得不說 Handler 在安卓中的地位真的是很牛逼 見解不到的地方歡迎大家指出