Rxjava 2.x 原始碼系列 - 變換操作符 Map(上)
前言
在上一篇部落格 Rxjava 2.x 原始碼系列 - 執行緒切換 (上) 我們講解到,Observable#subscribeOn 是如何控制上游 Observable 的執行執行緒的,他的實質是將 Observable#subscribe(Observer) 的操作放在了指定執行緒,當我們呼叫 subcribe 的時候,它的過程是從下往上的,即下面的 Observable 呼叫上面的 Observable。用下面的流程圖表示如下。
接下來,我們先來回顧一下,Observable 與 Observer 之間是如何訂閱的
簡單來說就是,當我們呼叫 Observable 的 subsribe 方法的時候,會呼叫當前對應 observbale 的 subscribeActual 方法,在該方法裡面,會呼叫 observer 的 onSubeciber 方法,並呼叫對應 ObservableOnSubscirbe 的 subcribe 的方法,並將 ObservableEmitter 作為方法引數暴露出去。而 ObservableEmitter 持有我們的 Observer 的引用,當我們呼叫 ObservableEmitter 的 onNext,onErrot,onComplete 方法的時候,會呼叫他持有的 Observer 的相應的方法。
這篇部落格主要講解以下問題:
- observeOn 是如何控制 Observer 的回撥執行緒的
Observable#observeOn 方法
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}
複製程式碼
observeOn 的套路跟 Observable.create 方法的套路基本一樣,都是先判斷是否為空,不為 null,用一個新的類包裝起來,並持有上游的引用 source。這裡我們的包裝類是 ObservableObserveOn。
這裡我們來看一下 ObservableObserveOn
public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
final boolean delayError;
final int bufferSize;
public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
super(source);
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
// 如果是當前執行緒,直接低啊用
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
// 否則,通過 worker 的形式呼叫
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
}
複製程式碼
從第一篇部落格 Rxjava 2.x 原始碼系列 - 基礎框架分析,我們知道,當我們呼叫 Observable.subscibe(observer) 方法的時候,會呼叫到 對應的 Observable 例項的 subscribeActual 方法,而這裡我們的 Observable 為 ObservableObserveOn 。
在 ObservableObserveOn.subscribeActual 方法中,首先會判斷 scheduler instanceof TrampolineScheduler (是否是當前執行緒),true 的話,會直接呼叫 source.subscribe(observer)。否則,先用 ObserveOnObserver 包裝 observer,再呼叫 source.subscribe 方法
接下來,我們一起來看一下 ObserveOnObserver 類
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
final Observer<? super T> actual;
}
public abstract class BasicIntQueueDisposable<T>
extends AtomicInteger
implements QueueDisposable<T> {
複製程式碼
ObserveOnObserver 繼承於 BasicIntQueueDisposable,實現 Observer, Runnable 介面,而 BasicIntQueueDisposable extends AtomicInteger ,是原子操作類。
其中,還有一個很重要的屬性 actual ,即是實際的 observer。
複製程式碼
接下來,我們來看一下幾個重要的方法:
onNext,onError,onComplete,onSubscribition
public void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
-------
if (m == QueueDisposable.SYNC) {
sourceMode = m;
queue = qd;
done = true;
actual.onSubscribe(this);
schedule();
return;
}
if (m == QueueDisposable.ASYNC) {
sourceMode = m;
queue = qd;
actual.onSubscribe(this);
return;
}
}
queue = new SpscLinkedArrayQueue<T>(bufferSize);
actual.onSubscribe(this);
}
}
@Override
public void onNext(T t) {
if (done) {
return;
}
------
schedule();
}
@Override
public void onError(Throwable t) {
if (done) {
RxJavaPlugins.onError(t);
return;
}
----
schedule();
}
@Override
public void onComplete() {
if (done) {
return;
}
----
schedule();
}
複製程式碼
在 onNext,onError,onComplete 方法中首先都會先判斷是否 done,如果沒有的話,會呼叫 schedule() 方法。
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
複製程式碼
而在 schedule() 方法中,直接呼叫 Worker 的 schedule 方法,這樣就會執行我們當前 ObserveOnObserver 的 run 方法,
public void run() {
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
複製程式碼
在 drainFused 和 drainNormal 方法中,會根據狀態去呼叫 actual(外部傳入的 observer) 的 onNext、onError、onComplete 方法。因此 observer 的回撥所在的執行緒將取決於外部傳入的 scheduler 的 schedule 方法所在的執行緒。
假設我們傳入的是 observeOn(AndroidSchedulers.mainThread())
public final class 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;
}
});
/** A {@link Scheduler} which executes actions on the Android main thread. */
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
---
}
複製程式碼
private static final class HandlerWorker extends Worker {
private final Handler handler;
private volatile boolean disposed;
HandlerWorker(Handler handler) {
this.handler = handler;
}
@Override
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
if (run == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
if (disposed) {
return Disposables.disposed();
}
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));
// Re-check disposed state for removing in case we were racing a call to dispose().
if (disposed) {
handler.removeCallbacks(scheduled);
return Disposables.disposed();
}
return scheduled;
}
}
複製程式碼
從上面的分析我們知道 observer 的回撥所在的執行緒將取決於外部傳入的 scheduler 的 schedule 方法所在的執行緒。即 指定 observeOn(AndroidSchedulers.mainThread()) 之後,將取決於 HandlerWorker 的 schedule 方法執行的執行緒,在該方法中,很明顯執行於主執行緒。
總結
控制 Observer 的回撥實際是放到 ObservableObserveOn 的 run 方法中,即 ObservableObserveOn 的 run 執行在主執行緒, Observer 的回撥也發生在主執行緒,而 ObservableObserveOn 的 run 執行在哪個執行緒,取決於 外部傳入的 scheduler。因此, 當外部傳入的 scheduler 的 schedule 方法在主執行緒,那麼 observer 也在主執行緒回撥。
掃一掃,歡迎關注我的公眾號。如果你有好的文章,也歡迎你的投稿。