Rxjava 過程分析四之 observeOn

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 把運行結果切換到了自己指定的線程中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章