Rxjava 過程分析四之 observeOn
說明
- 本文只分析 observeOn 主要思想和流程, 如果想看 subscribeOn 請看上一篇文章
基本使用
Flowable.create(new FlowableOnSubscribe<String>() {
@Override
public void subscribe(FlowableEmitter<String> emitter) throws Exception {
// emitter.onNext("");
// emitter.onError();
// emitter.onComplete();
}
}, BackpressureStrategy.LATEST)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<String>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
我們經常使用 subscribeOn 去切換到主線程去更新 ui 之類的。 爲什麼一行代碼就可以把運行的線程給切換了呢? 內部咋實現的呢? handler? 我們一點點看源碼去揭開。
引發的思考
- 這貨是怎麼把線程給切換過來的呢? 怎麼實現的呢?
- 這貨可以使用多次嗎?
源碼分析
還是老樣子, 前一堆和後一堆, 我們不再分析, 如果不明白或者需要回顧的可以看以前的幾篇文章。 那麼我們從 observeOn 開始吧。
public final Flowable<T> observeOn(Scheduler scheduler, boolean delayError) {
return observeOn(scheduler, delayError, bufferSize());
}
然後調用到的方法直接點
public final Flowable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
return new FlowableObserveOn<T>(this, scheduler, delayError, bufferSize);
}
你看看, Rxjava 的一模一樣, 都是隻是新建了一個 Flowable, 然後把當前的 Flowable 作爲參數傳入, 進行賦值。 通過我們前三篇的分析, 別浪費時間了, 直接看 FlowableObserveOn 中的 subscribeActual 吧。
public void subscribeActual(Subscriber<? super T> s) {
Worker worker = scheduler.createWorker();
source.subscribe(new ObserveOnSubscriber<T>(s, worker, delayError, prefetch));
}
看吧, 猜就猜到了, 肯定是連鎖反應的訂閱了。 應爲我們還不知道當前的 worker 內部是怎麼實現的呢, 所以我們還是一行一行的看吧。
第一行
我們傳入的 AndroidSchedulers.mainThread(), 所以我們看看這個 Schedulers 是怎麼實現的。
public static Scheduler mainThread() {
return MAIN_THREAD;
}
MAIN_THREAD 是什麼呀, 擡頭一看, 是成員變量。 我們整體先看看這個類吧。
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);
}
/** A {@link Scheduler} which executes actions on {@code looper}. */
public static Scheduler from(Looper looper) {
if (looper == null) throw new NullPointerException("looper == null");
return new HandlerScheduler(new Handler(looper));
}
private AndroidSchedulers() {
throw new AssertionError("No instances.");
}
}
從源碼中我們發現, 其實我們可以使用這個切換到任何線程呢, 不一定要走主線程,當然使用mainThead() 默認使用了 MainLooper 而已, 因爲可以傳入 Looper 去在任何線程中運行。 以我們的開發使用情況來看, 現在我們重點是看看 HandlerScheduler 是怎麼操作的呢。
final class HandlerScheduler extends Scheduler {
private final Handler handler;
HandlerScheduler(Handler handler) {
this.handler = handler;
}
@Override
public Worker createWorker() {
return new HandlerWorker(handler);
}
}
看到這裏你是否明白了, 爲什麼可以切換主線程了嗎? 不管是怎麼實現的。 其實應該在上一步就應該知道了, 因爲使用的是 Handler(MainLooper)。 走到這裏了我還想多說一句, 還記得我們介紹 subscribeOn 的這裏時, 我們也說了好多, 就是操作方法一樣, 只是實現不一樣而已。 我記得沒錯的話, 在 subscribeOn 裏應該時一個線程池, 而在這裏換成了一個 Handler 而已。
第二行
其實和原來的一模一樣, 在這裏把上層的 Flowable 進行了連鎖形式的訂閱。 然後是上層的 Flowable 上游發射流出數據, 會直接到 ObserveOnSubscriber 中相應的方法, 那麼好, 讓我們直接看 ObserveOnSubscriber 中 onNext 時怎麼操作才能到主線程的把, 反正跟 Handler 沒跑了。
public final void onNext(T t) {
if (done) {
return;
}
if (sourceMode == ASYNC) {
trySchedule();
return;
}
if (!queue.offer(t)) {
upstream.cancel();
error = new MissingBackpressureException("Queue is full?!");
done = true;
}
trySchedule();
}
我們主要分析主流程, 我們看到不管哪種方式都會調用到 trySchedule(), 我們就進去看下
final void trySchedule() {
worker.schedule(this);
}
看到了嗎。 把當前 Runable 放到 worker 裏了, 我們看下 HandlerScheduler 是怎麼操作的。
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
run = 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)));
return scheduled;
}
核心方法如下, 我們看到又 new 出來一箇中間的 ScheduledRunnable, 把我們要執行的傳了進去, 然後使用 Handler 不管是否延遲把, 會調用到 ScheduledRunnable 的 run 方法, 讓我們看看裏面怎麼實現的。
public void run() {
try {
delegate.run();
} catch (Throwable t) {
}
}
這也太簡單了把, 直接調用到了我們傳進來的那個 Runnable。 那麼好饒了這麼一大圈就是爲了, 我們的 Run 方法可以運行在指定的線程中。 好了, 我們返回到最開始去看看我們的 ObserveOnSubscriber 中 run 方法執行了什麼。
public final void run() {
if (outputFused) {
runBackfused();
} else if (sourceMode == SYNC) {
runSync();
} else {
runAsync();
}
}
呀呵, 根據不同條件做不同的操作呢, 反正都是在我們指定的線程中運行呢。
我們隨便看一個把 runSync 把
void runSync() {
final Subscriber<? super T> a = downstream;
final SimpleQueue<T> q = queue;
v = q.poll();
a.onNext(v);
}
把其他我們分析主流程不太關注的流程去掉,看到這幾行代碼是不是覺得特簡單呢。
前面的疑惑問題
- 這貨是怎麼把線程給切換過來的呢? 怎麼實現的呢?
很明顯, 是通過 handler 去處理的, 當然具體在哪個線程中, 就要看 looper 了。
- 這貨可以使用多次嗎?
爲啥不可以, 沒使用一次, 就相當於, 通過 Handler 把運行結果切換到了自己指定的線程中。