前言
通過前一篇的RxJava2 是如何實現執行緒切換的 (上)我們已經知道了在RxJava中,subscribeOn 將上游執行緒切換到指定的子執行緒是如何實現的。這裡就接著來看,observeOn 是如何將下游執行緒切換到指定執行緒的。
RxJava - subscribeOn
這裡可以通過UML圖簡單回顧一下subscribeOn的原理。
通過 subscribeOn 我們完成了以下操作:
- 建立了一個 ObservableSubscribeOn 物件,本質上來說他就是一個Observable,他同時實現了 AbstractObservableWithUpstream(HasUpstreamObservableSource )這樣一個介面,是他變了一個擁有上游的Observeable。
- 在 ObservableSubscribeOn 的 subscribeActual 方法中
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
複製程式碼
將真正的 subscribe 操作安置在了SubscribeTask這樣個一個Runnable當中,這個 Runnable 將由scheduler 這個排程器負責啟動,因此就把上游操作放到了 scheduler 所在的執行緒中。
- Schedulers.newThread()或者Schedulers.io() 都是通過工廠方法的模式建立了某種指定型別的執行緒, 當這個特定的執行緒執行是,就是執行真實的 subscribe 方法,這樣就把上游操作放到了一個特定的執行緒中去執行。
RxJava - observeOn
簡單回顧完 subscribeOn 之後,我們就來看看 observeOn 是如何工作的。
其實,瞭解 subscribeOn 的原理之後,再來看 observeOn 就簡單多了,類的命名及實現思路都有很多相似之處,可以對照著理解。
RxJava的程式碼寫的非常巧妙,可以說是百讀不厭,可以學習的地方特別多。為了避免陷入只見樹木不見森林的噩夢,我們就帶著以下問題去探索 observeOn 的奧祕。
- 在 Android 中執行緒間傳遞訊息會使用 Handler,這裡是否使用?又是如何使用的?
- AndroidSchedulers.mainThread() 做了什麼 ?
- 下游任務是如何保證被分配到指定執行緒的。
示例
private void multiThread() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("This msg from work thread :" + Thread.currentThread().getName());
sb.append("\nsubscribe: currentThreadName==" + Thread.currentThread().getName());
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.e(TAG, "accept: s= " + s);
}
});
}
複製程式碼
我們還是以這段程式碼為例,來看看 observeOn 的工作原理。這裡通過observeOn(AndroidSchedulers.mainThread())將下游執行緒切換到了我們非常熟悉的 Android UI 執行緒。這樣就可以確保我們在下游所有的操作都是在 UI 執行緒中完成。這裡和討論 subscribeOn 一樣,我們就從這句程式碼出發,看看這背後到底發生了什麼。
有了上一篇的經驗,我們知道 AndroidSchedulers.mainThread() 一定去建立了某種型別的排程器,為了方便後面的敘述,這一次我們先從排程器的建立說起,後面再看 observeOn() 的具體實現。
需要注意的是 AndroidSchedulers 並不是 RxJava 的一部分,是為了在 Android 中方便的使用 RxJava 而專門設計的一個排程器實現,原始碼RxAndroid 設計非常巧妙;使用前記得在gradle檔案中配置依賴。
AndroidSchedulers.mainThread()
下面就來看看 AndroidSchedulers.mainThread() 這個我們非常熟悉的 Scheduler 是如何建立的。
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;
}
});
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
}
複製程式碼
這裡我們可以認為,當呼叫AndroidSchedulers.mainThread() 時,返回了一個HandlerScheduler 的例項,而這個例項使用到了我們非常熟悉的 Handler。那麼重點就來到HandlerScheduler 了。
final class HandlerScheduler extends Scheduler {
private final Handler handler;
HandlerScheduler(Handler handler) {
this.handler = handler;
}
@Override
public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
if (run == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
run = RxJavaPlugins.onSchedule(run);
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
handler.postDelayed(scheduled, Math.max(0L, unit.toMillis(delay)));
return scheduled;
}
@Override
public Worker createWorker() {
return new HandlerWorker(handler);
}
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, Math.max(0L, 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;
}
@Override
public void dispose() {
disposed = true;
handler.removeCallbacksAndMessages(this /* token */);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
private static final class ScheduledRunnable implements Runnable, Disposable {
private final Handler handler;
private final Runnable delegate;
private volatile boolean disposed;
ScheduledRunnable(Handler handler, Runnable delegate) {
this.handler = handler;
this.delegate = delegate;
}
@Override
public void run() {
try {
delegate.run();
} catch (Throwable t) {
IllegalStateException ie =
new IllegalStateException("Fatal Exception thrown on Scheduler.", t);
RxJavaPlugins.onError(ie);
Thread thread = Thread.currentThread();
thread.getUncaughtExceptionHandler().uncaughtException(thread, ie);
}
}
@Override
public void dispose() {
disposed = true;
handler.removeCallbacks(this);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
}
複製程式碼
這個類雖然很簡單,但是設計非常巧妙。
-
首先 HandlerScheduler 是一個 Scheduler ,通過建構函式他獲取到了主執行緒所在的 Handler例項。而在他的 createWorker() 方法中,他又通過這個 Handler 例項建立了一個HandlerWorker 的例項,這個HandlerWorker 本質上就是一個 Worker。在他的 schedule 方法中,建立了一個 ScheduleRunnable 物件,並會把這個Runnable物件通過 handler 的 sendMessageDelayed 方法傳送出去,而我們知道這個 Handler 是主執行緒,這樣在下游中,就把任務從某個子執行緒轉移到了UI執行緒。
-
ScheduleRunnable 不但實現了 Runnable ,而且實現了我們看到過無數次的 Disposable 。
@Override
public void run() {
try {
delegate.run();
} catch (Throwable t) {
}
}
@Override
public void dispose() {
disposed = true;
handler.removeCallbacks(this);
}
複製程式碼
這樣,正確情況下 run 方法會正常執行執行緒中的任務,而一旦 disposable 物件執行了dispose()方法,那麼 handler.removeCallbacks(this),就可確保在 handler 的 dispatchMessage 方法中,不會在執行任何操作,從而達到了 dispose 的效果。
observeOn
下面就來看看 Observable 中的 observeOn 方法
Observable.java --- observeOn
public final Observable<T> observeOn(Scheduler scheduler) {
return observeOn(scheduler, false, bufferSize());
}
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));
}
複製程式碼
這個方法的實現和 subscribeOn 的實現非常相似,多了兩個引數 delayError 和 buffersize 。 buffersize 可以認為是RxJava內部的一個靜態變數,預設情況下他的值是128。通過我們之前的經驗,這裡可以把 observeOn 的過程簡化如下:
new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize)
複製程式碼
也就是說 observeOn 這個操作符給我們返回了一個 ObservableObserveOn 物件。很容易想到他也是一個 Observeable。那麼我們就去看看這個 ObservableObserveOn 到底是什麼?我們最關心的 subscribeActual 方法他又是怎樣實現的。
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 {
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
}
複製程式碼
和 ObservableSubscribeOn 一樣,他也繼承了 AbstractObservableWithUpstream ,這樣他也是一個擁有上游的 Observeable,他的建構函式很簡單,沒什麼可以說。這裡我們重點關注一下 subscribeActual 方法的實現。這裡我們的使用的Scheduler 例項是 AndroidSchedulers.mainThread(),因此就按 else的邏輯分析。
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
複製程式碼
通過 scheduler.createWorker() 建立了 Worker 這個物件。這裡結合之前對 AndroidSchedulers.mainThread() 的分析,此處的 worker 物件是就是一個持有主執行緒 handler 引用的 Worker。
接著用這個worker又建立了一個ObserveOnObserver物件。看看這個類的實現。
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable { ....}
複製程式碼
這個類功能非常強大,首先是一個 Observer ,同時也是一個Runnable,並且還繼承了 BasicIntQueueDisposable(保證原子性、擁有操作佇列功能和 Disposable功能)。
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
複製程式碼
我們關注一下這行程式碼,根據之前的說法這裡的 source 是其父類(AbstractObservableWithUpstream)中的成員變數,也就是說是上游,那麼當前ObservableObserveOn 的上游是誰呢? 就是我們上一篇所說的 ObservableSubscribeOn 。
因此,當這裡開始執行訂閱方法 subscribe() 後,將以如下順序響應:
Observable.subscribe--->Observable.subscribeActual---> ObservableObserveOn.subscribeActual---> ObservableSubscribeOn.subscribeActual--->ObservableCreate.subscribeActual
這些方法的引數均為 observer,通過層層回撥,最後的 subscribeActual(Observer<? super T> observer) 執行時,這個 observer 持有之前幾個 observer 的引用。
我們再看一下 ObservableCreate.subscribeActual
@Override
protected void subscribeActual(Observer<? super T> observer) {
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
observer.onSubscribe(parent);
try {
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
複製程式碼
可以看到,這裡首先會觸發 observer.onSubscribe ,我們再看一下 ObservableSubscribeOn.subscribeActual
@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
複製程式碼
好了,這樣我們又回到了原點:
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
複製程式碼
回到了最初的 Observer:ObserveOnObserver
這個 ObserveOnObserver 持有我們一開始建立的observer,也就是一個Consumer物件。
下面就來看看這個 ObserveOnObserver
- 建構函式
ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
this.actual = actual;
this.worker = worker;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
複製程式碼
這裡指的注意的一點 ,actual 其實就是observer
- onSubscribe
@Override
public void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
this.s = s;
// 現階段,我們用到的Disposable 都是單個的,暫時不討論其
//為QueueDisposable的情況
queue = new SpscLinkedArrayQueue<T>(bufferSize);
actual.onSubscribe(this);
}
}
複製程式碼
在ObservableCreate.subscribeActual 中我們知道,當執行subscribe 方法後,首先會執行 observer的 onSubscribe 方法。這裡的實現非常簡單,就是建立了一個queue,並觸發了這個 observer 自己的 onSubscribe 方法。
- onNext
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
複製程式碼
在 onNext 中會執行 scheule() 方法。
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
複製程式碼
這個地方就有意思了,前面說過這裡的 worker 是一個持有主執行緒handler 的Worker物件,當他的 schedule 執行時,就會把特定的執行緒任務通過Handler.postDelay 方法轉移到主線中去執行 。
那麼這裡的this 又是什麼呢?前面我們說過,ObserveOnObserver 這個類功能非常強大,他是一個Runnable,那麼這裡就是執行他自己的run方法嘍,我們趕緊看看。
@Override
public void run() {
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
複製程式碼
這裡有一個引數 outputFused 他預設是false,至於他什麼時候為true,不作為這裡討論的重點。
void drainNormal() {
int missed = 1;
final SimpleQueue<T> q = queue;
final Observer<? super T> a = actual;
for (;;) {
if (checkTerminated(done, q.isEmpty(), a)) {
return;
}
for (;;) {
boolean d = done;
T v;
try {
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
worker.dispose();
return;
}
boolean empty = v == null;
if (checkTerminated(d, empty, a)) {
return;
}
if (empty) {
break;
}
a.onNext(v);
}
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
複製程式碼
這裡大概就是通過一個死迴圈,不斷從 onSubscribe 方法中建立的佇列中取出事件,執行observer 的 onNext方法。而當為例為空時,就會執行worker.dispose 取消整個事件流,同時從Handler中移除所有訊息。
最後在看一眼 onComplete ,onError 和整個類似
@Override
public void onComplete() {
if (done) {
return;
}
done = true;
schedule();
}
複製程式碼
可以看到這裡的處理也很簡單,done 設定為 true .這樣最後便完成了下游事件的執行。
最後
好了,由於一些無以訴說的原因,經歷了很久終於把 RxJava 執行緒切換的下篇給完成了。