響應(yīng)式編程與RxJava

1. 響應(yīng)式編程

1.1 響應(yīng)式編程概念

  • 響應(yīng)式編程是一種通過(guò)異步和數(shù)據(jù)流來(lái)構(gòu)建事物關(guān)系的編程模型。
  • 事物的關(guān)系 也可以說(shuō)成是 業(yè)務(wù)邏輯 ,是響應(yīng)式編程的核心理念。
  • 數(shù)據(jù)流異步 是實(shí)現(xiàn)這個(gè)核心理念的關(guān)鍵。異步和數(shù)據(jù)流都是為了正確的構(gòu)建事物的關(guān)系而存在的。

1.2 響應(yīng)式編程demo

int a=1;
int b=a+1;
System.out.print(“b=”+b)    //  b=2
a=10;
System.out.print(“b=”+b)    //  b=2

上面是一段很常見(jiàn)的代碼,簡(jiǎn)單的賦值打印語(yǔ)句,但是這種代碼有一個(gè)缺陷,那就是如果我們想表達(dá)的并不是一個(gè)賦值動(dòng)作,而是b和a之間的關(guān)系,即無(wú)論a如何變化,b永遠(yuǎn)比a大1。那么可以想見(jiàn),我們就需要花額外的精力去構(gòu)建和維護(hù)一個(gè)b和a的關(guān)系。
而響應(yīng)式編程的想法正是企圖用某種操作符幫助你構(gòu)建這種關(guān)系。
它的思想完全可以用下面的代碼片段來(lái)表達(dá):

int a=1;
int b <= a+1;   // <= 符號(hào)只是表示a和b之間關(guān)系的操作符
System.out.print(“b=”+b)    //  b=2
a=10;
System.out.print(“b=”+b)    //  b=11

響應(yīng)式編程的思想,它希望有某種方式能夠構(gòu)建關(guān)系,而不是執(zhí)行某種賦值命令。

應(yīng)用初始化.png

比如在收單應(yīng)用初始化邏輯中,先完成SDK初始化,數(shù)據(jù)庫(kù)初始化,簽到,才會(huì)跳轉(zhuǎn)到交易菜單界面。

在響應(yīng)式編程中,這一流程可以這樣解讀


應(yīng)用初始化2.png

在初始化過(guò)程中,SDK初始化,數(shù)據(jù)庫(kù)初始化,簽到這些業(yè)務(wù)完成之后才會(huì)去安排頁(yè)面跳轉(zhuǎn)的操作,那么這些上游的業(yè)務(wù)在自己工作完成之后,就需要通知下游,通知下游的方式有很多種,響應(yīng)式編程的方式就是通過(guò)數(shù)據(jù)(事件)流。

每一個(gè)業(yè)務(wù)完成后,都會(huì)有一條數(shù)據(jù)(一個(gè)事件)流向下游,下游的業(yè)務(wù)收到這條數(shù)據(jù)(這個(gè)事件),才會(huì)開(kāi)始自己的工作。

我們能發(fā)現(xiàn)SDK初始化,數(shù)據(jù)庫(kù)初始化,簽到這三個(gè)業(yè)務(wù)本身相互獨(dú)立,應(yīng)當(dāng)在不同的線(xiàn)程環(huán)境中執(zhí)行,以保證他們不會(huì)相互阻塞。而假如沒(méi)有異步編程,我們可能只能在一個(gè)線(xiàn)程中順序調(diào)用這三個(gè)相對(duì)耗時(shí)較多的業(yè)務(wù),最終再去做頁(yè)面跳轉(zhuǎn),這樣做不僅沒(méi)有忠實(shí)反映業(yè)務(wù)本來(lái)的關(guān)系,而且會(huì)讓你的程序“反應(yīng)”更慢。

總的來(lái)說(shuō),異步和數(shù)據(jù)流都是為了正確的構(gòu)建事務(wù)的關(guān)系而存在的。只不過(guò),異步是為了區(qū)分出無(wú)關(guān)的事務(wù),而數(shù)據(jù)流(事件流)是為了聯(lián)系起有關(guān)的事務(wù)。

2. RxJava

Rx是響應(yīng)式拓展,即支持響應(yīng)式編程的一種拓展,用來(lái)處理事件和異步任務(wù)。

2.1 RxJava的優(yōu)點(diǎn)

簡(jiǎn)潔。而且當(dāng)業(yè)務(wù)越繁瑣越復(fù)雜時(shí)這一點(diǎn)就越顯出優(yōu)勢(shì)——它能夠保持簡(jiǎn)潔。

2.2 RxJava的基本概念

我們都知道監(jiān)聽(tīng)者模式,訂閱模式這些概念。而Observable和Subscribers的英文意思就是如此。我們大概也知道差不多和監(jiān)聽(tīng)者模式差不多。

  • Observable事件源,被觀(guān)察者。
  • Observer / Subcriblers 觀(guān)察者,事件訂閱者
  • subscribe() 方法,綁定Observable與Subcribler或者Observabler
  • 事件 (包括 onNext,onComplete,onError 等事件)

以第一章的初始化應(yīng)用為例:

Observable obserInitSDK=Observable.create((context)->{initSDK(context)}).subscribeOn(Schedulers.newThread())

Observable obserInitDB=Observable.create((context)->{initDatabase(context)}).subscribeOn(Schedulers.newThread())

Observable obserLogin=Observable.create((context)->{Login(context)})
                            .subscribeOn(Schedulers.newThread())
// 合并多個(gè)Observables的發(fā)射物                           
Observable observable = Observable.merge(obserInitSDK,obserInitDB,obserLogin)
// 訂閱被觀(guān)察者
observable.subscribe(()->{startActivity()})

當(dāng)initSDK,initDB,Login都是耗時(shí)較長(zhǎng)的操作時(shí),遵照業(yè)務(wù)關(guān)系編寫(xiě)響應(yīng)式代碼可以極大的提高程序的執(zhí)行效率,降低阻塞。
從上面代碼中,可以看出,響應(yīng)式編程有如下優(yōu)點(diǎn)

  • 在業(yè)務(wù)層面實(shí)現(xiàn)代碼邏輯分離,方便后期維護(hù)和拓展
  • 極大提高程序響應(yīng)速度,充分發(fā)掘CPU的能力
  • 幫助開(kāi)發(fā)者提高代碼的抽象能力和充分理解業(yè)務(wù)邏輯
  • Rx豐富的操作符會(huì)幫助我們極大的簡(jiǎn)化代碼邏輯

2.3 操作符決策樹(shù)

RxJava的幾種主要操作符:

  • 創(chuàng)建操作:直接創(chuàng)建一個(gè)Observable
  • 組合操作:組合多個(gè)Observable
  • 變換操作:對(duì)Observable發(fā)射的數(shù)據(jù)執(zhí)行變換操作
  • 過(guò)濾操作:從Observable發(fā)射的數(shù)據(jù)中取特定的值
  • 條件/布爾/過(guò)濾操作:轉(zhuǎn)發(fā)Observable的部分值
  • 算術(shù)/聚合操作:對(duì)Observable發(fā)射的數(shù)據(jù)序列求值

創(chuàng)建操作

用于創(chuàng)建Observable的操作符

  • Create — 通過(guò)調(diào)用觀(guān)察者的方法從頭創(chuàng)建一個(gè)Observable
  • Defer — 在觀(guān)察者訂閱之前不創(chuàng)建這個(gè)Observable,為每一個(gè)觀(guān)察者創(chuàng)建一個(gè)新的Observable
  • Empty/Never/Throw — 創(chuàng)建行為受限的特殊Observable
  • From — 將其它的對(duì)象或數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為Observable
  • Interval — 創(chuàng)建一個(gè)定時(shí)發(fā)射整數(shù)序列的Observable
  • Just — 將對(duì)象或者對(duì)象集合轉(zhuǎn)換為一個(gè)會(huì)發(fā)射這些對(duì)象的Observable
  • Range — 創(chuàng)建發(fā)射指定范圍的整數(shù)序列的Observable
  • Repeat — 創(chuàng)建重復(fù)發(fā)射特定的數(shù)據(jù)或數(shù)據(jù)序列的Observable
  • Start — 創(chuàng)建發(fā)射一個(gè)函數(shù)的返回值的Observable
  • Timer — 創(chuàng)建在一個(gè)指定的延遲之后發(fā)射單個(gè)數(shù)據(jù)的Observable

變換操作

用于對(duì)Observable發(fā)射的數(shù)據(jù)進(jìn)行變換

  • Buffer — 緩存,可以簡(jiǎn)單的理解為緩存,它定期從Observable收集數(shù)據(jù)到一個(gè)集合,然后把這些數(shù)據(jù)集合打包發(fā)射,而不是一次發(fā)射一個(gè)
  • FlatMap — 扁平映射,將Observable發(fā)射的數(shù)據(jù)變換為Observables集合,然后將這些Observable發(fā)射的數(shù)據(jù)平坦化的放進(jìn)一個(gè)單獨(dú)的Observable,可以認(rèn)為是一個(gè)將嵌套的數(shù)據(jù)結(jié)構(gòu)展開(kāi)的過(guò)程。
  • GroupBy — 分組,將原來(lái)的Observable分拆為Observable集合,將原始Observable發(fā)射的數(shù)據(jù)按Key分組,每一個(gè)Observable發(fā)射一組不同的數(shù)據(jù)
  • Map — 映射,通過(guò)對(duì)序列的每一項(xiàng)都應(yīng)用一個(gè)函數(shù)變換Observable發(fā)射的數(shù)據(jù),實(shí)質(zhì)是對(duì)序列中的每一項(xiàng)執(zhí)行一個(gè)函數(shù),函數(shù)的參數(shù)就是這個(gè)數(shù)據(jù)項(xiàng)
  • Scan — 掃描,對(duì)Observable發(fā)射的每一項(xiàng)數(shù)據(jù)應(yīng)用一個(gè)函數(shù),然后按順序依次發(fā)射這些值
  • Window — 窗口,定期將來(lái)自O(shè)bservable的數(shù)據(jù)分拆成一些Observable窗口,然后發(fā)射這些窗口,而不是每次發(fā)射一項(xiàng)。類(lèi)似于Buffer,但Buffer發(fā)射的是數(shù)據(jù),Window發(fā)射的是Observable,每一個(gè)Observable發(fā)射原始Observable的數(shù)據(jù)的一個(gè)子集

過(guò)濾操作

用于從Observable發(fā)射的數(shù)據(jù)中進(jìn)行選擇

  • Debounce — 只有在空閑了一段時(shí)間后才發(fā)射數(shù)據(jù),通俗的說(shuō),就是如果一段時(shí)間沒(méi)有操作,就執(zhí)行一次操作
  • Distinct — 去重,過(guò)濾掉重復(fù)數(shù)據(jù)項(xiàng)
  • ElementAt — 取值,取特定位置的數(shù)據(jù)項(xiàng)
  • Filter — 過(guò)濾,過(guò)濾掉沒(méi)有通過(guò)謂詞測(cè)試的數(shù)據(jù)項(xiàng),只發(fā)射通過(guò)測(cè)試的
  • First — 首項(xiàng),只發(fā)射滿(mǎn)足條件的第一條數(shù)據(jù)
  • IgnoreElements — 忽略所有的數(shù)據(jù),只保留終止通知(onError或onCompleted)
  • Last — 末項(xiàng),只發(fā)射最后一條數(shù)據(jù)
  • Sample — 取樣,定期發(fā)射最新的數(shù)據(jù),等于是數(shù)據(jù)抽樣,有的實(shí)現(xiàn)里叫ThrottleFirst
  • Skip — 跳過(guò)前面的若干項(xiàng)數(shù)據(jù)
  • SkipLast — 跳過(guò)后面的若干項(xiàng)數(shù)據(jù)
  • Take — 只保留前面的若干項(xiàng)數(shù)據(jù)
  • TakeLast — 只保留后面的若干項(xiàng)數(shù)據(jù)

組合操作

用于將多個(gè)Observable組合成一個(gè)單一的Observable

  • And/Then/When — 通過(guò)模式(And條件)和計(jì)劃(Then次序)組合兩個(gè)或多個(gè)Observable發(fā)射的數(shù)據(jù)集
  • CombineLatest — 當(dāng)兩個(gè)Observables中的任何一個(gè)發(fā)射了一個(gè)數(shù)據(jù)時(shí),通過(guò)一個(gè)指定的函數(shù)組合每個(gè)Observable發(fā)射的最新數(shù)據(jù)(一共兩個(gè)數(shù)據(jù)),然后發(fā)射這個(gè)函數(shù)的結(jié)果
  • Join — 無(wú)論何時(shí),如果一個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù)項(xiàng),只要在另一個(gè)Observable發(fā)射的數(shù)據(jù)項(xiàng)定義的時(shí)間窗口內(nèi),就將兩個(gè)Observable發(fā)射的數(shù)據(jù)合并發(fā)射
  • Merge — 將兩個(gè)Observable發(fā)射的數(shù)據(jù)組合并成一個(gè)
  • StartWith — 在發(fā)射原來(lái)的Observable的數(shù)據(jù)序列之前,先發(fā)射一個(gè)指定的數(shù)據(jù)序列或數(shù)據(jù)項(xiàng)
  • Switch — 將一個(gè)發(fā)射Observable序列的Observable轉(zhuǎn)換為這樣一個(gè)Observable:它逐個(gè)發(fā)射那些Observable最近發(fā)射的數(shù)據(jù)
  • Zip — 打包,使用一個(gè)指定的函數(shù)將多個(gè)Observable發(fā)射的數(shù)據(jù)組合在一起,然后將這個(gè)函數(shù)的結(jié)果作為單項(xiàng)數(shù)據(jù)發(fā)射

錯(cuò)誤處理

用于從錯(cuò)誤通知中恢復(fù)

  • Catch — 捕獲,繼續(xù)序列操作,將錯(cuò)誤替換為正常的數(shù)據(jù),從onError通知中恢復(fù)
  • Retry — 重試,如果Observable發(fā)射了一個(gè)錯(cuò)誤通知,重新訂閱它,期待它正常終止

輔助操作

用于處理Observable的操作符

  • Delay — 延遲一段時(shí)間發(fā)射結(jié)果數(shù)據(jù)
  • Do — 注冊(cè)一個(gè)動(dòng)作占用一些Observable的生命周期事件,相當(dāng)于Mock某個(gè)操作
  • Materialize/Dematerialize — 將發(fā)射的數(shù)據(jù)和通知都當(dāng)做數(shù)據(jù)發(fā)射,或者反過(guò)來(lái)
  • ObserveOn — 指定觀(guān)察者觀(guān)察Observable的調(diào)度程序(工作線(xiàn)程)
  • Serialize — 強(qiáng)制Observable按次序發(fā)射數(shù)據(jù)并且功能是有效的
  • Subscribe — 收到Observable發(fā)射的數(shù)據(jù)和通知后執(zhí)行的操作
  • SubscribeOn — 指定Observable應(yīng)該在哪個(gè)調(diào)度程序上執(zhí)行
  • TimeInterval — 將一個(gè)Observable轉(zhuǎn)換為發(fā)射兩個(gè)數(shù)據(jù)之間所耗費(fèi)時(shí)間的Observable
  • Timeout — 添加超時(shí)機(jī)制,如果過(guò)了指定的一段時(shí)間沒(méi)有發(fā)射數(shù)據(jù),就發(fā)射一個(gè)錯(cuò)誤通知
  • Timestamp — 給Observable發(fā)射的每個(gè)數(shù)據(jù)項(xiàng)添加一個(gè)時(shí)間戳
  • Using — 創(chuàng)建一個(gè)只在Observable的生命周期內(nèi)存在的一次性資源

條件和布爾操作

用于單個(gè)或多個(gè)數(shù)據(jù)項(xiàng),也可用于Observable

  • All — 判斷Observable發(fā)射的所有的數(shù)據(jù)項(xiàng)是否都滿(mǎn)足某個(gè)條件
  • Amb — 給定多個(gè)Observable,只讓第一個(gè)發(fā)射數(shù)據(jù)的Observable發(fā)射全部數(shù)據(jù)
  • Contains — 判斷Observable是否會(huì)發(fā)射一個(gè)指定的數(shù)據(jù)項(xiàng)
  • DefaultIfEmpty — 發(fā)射來(lái)自原始Observable的數(shù)據(jù),如果原始Observable沒(méi)有發(fā)射數(shù)據(jù),就發(fā)射一個(gè)默認(rèn)數(shù)據(jù)
  • SequenceEqual — 判斷兩個(gè)Observable是否按相同的數(shù)據(jù)序列
  • SkipUntil — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到第二個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù),然后發(fā)射原始Observable的剩余數(shù)據(jù)
  • SkipWhile — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到一個(gè)特定的條件為假,然后發(fā)射原始Observable剩余的數(shù)據(jù)
  • TakeUntil — 發(fā)射來(lái)自原始Observable的數(shù)據(jù),直到第二個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù)或一個(gè)通知
  • TakeWhile — 發(fā)射原始Observable的數(shù)據(jù),直到一個(gè)特定的條件為真,然后跳過(guò)剩余的數(shù)據(jù)

算術(shù)和聚合操作

用于整個(gè)數(shù)據(jù)序列

  • Average — 計(jì)算Observable發(fā)射的數(shù)據(jù)序列的平均值,然后發(fā)射這個(gè)結(jié)果
  • Concat — 不交錯(cuò)的連接多個(gè)Observable的數(shù)據(jù)
  • Count — 計(jì)算Observable發(fā)射的數(shù)據(jù)個(gè)數(shù),然后發(fā)射這個(gè)結(jié)果
  • Max — 計(jì)算并發(fā)射數(shù)據(jù)序列的最大值
  • Min — 計(jì)算并發(fā)射數(shù)據(jù)序列的最小值
  • Reduce — 按順序?qū)?shù)據(jù)序列的每一個(gè)應(yīng)用某個(gè)函數(shù),然后返回這個(gè)值
  • Sum — 計(jì)算并發(fā)射數(shù)據(jù)序列的和

另外還有連接操作轉(zhuǎn)換操作,可以通過(guò)文檔查看使用方法。

2.4 RxJava 基礎(chǔ)框架解析

  • 先從比較常用的create方法看
public static Completable create(CompletableOnSubscribe source) {
        ObjectHelper.requireNonNull(source, "source is null");
        return RxJavaPlugins.onAssembly(new CompletableCreate(source));
    }

在 create 方法中,其實(shí)很簡(jiǎn)單,只是對(duì) source 進(jìn)行判空處理,并將 source 用 ObservableCreate 包裝起來(lái),并返回回去。下面讓我們一起來(lái)看一下 ObservableCreate方法

public final class CompletableCreate extends Completable {

    final CompletableOnSubscribe source;

    public CompletableCreate(CompletableOnSubscribe source) {
        this.source = source;
    }

    // daizy -- 持有了上游 source 的引用,并重寫(xiě) subscribeActual 方法
    @Override
    protected void subscribeActual(CompletableObserver observer) {
        Emitter parent = new Emitter(observer);
        observer.onSubscribe(parent);

        try {
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }

ObservableCreate 也很簡(jiǎn)單,它是 Observable 的子類(lèi),持有了上游 source 的引用,并重寫(xiě) subscribeActual 方法,這個(gè)方法要結(jié)合訂閱Subscribe源碼看。

@SchedulerSupport(SchedulerSupport.NONE)
    @Override
    public final void subscribe(CompletableObserver observer) {
        // 檢查 observer 是否為 null,為 null 拋出異常
        ObjectHelper.requireNonNull(observer, "observer is null");
        try {
            // RxJavaPlugins 插件的,暫時(shí)不管
            observer = RxJavaPlugins.onSubscribe(this, observer);
            // 檢查 observer 是否為 null,為 null 拋出異常
            ObjectHelper.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null CompletableObserver. Please check the handler provided to RxJavaPlugins.setOnCompletableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");

            subscribeActual(observer);
        } catch (NullPointerException ex) { // NOPMD
            throw ex;
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            RxJavaPlugins.onError(ex);
            throw toNpe(ex);
        }
    }

subscribe 方法也比較簡(jiǎn)單,大概可以分為以下兩步:

  • 第一步,對(duì)observer 進(jìn)行判空,為空則拋出異常
  • 第二步,調(diào)用 subscribeActual 方法,在Observable類(lèi) 中,subscribeActual 是一個(gè)抽象方法,要關(guān)注的是其實(shí)現(xiàn)類(lèi)的subscribeActual方法。從上面的分析,我們知道,當(dāng)我們調(diào)用 Observable create(ObservableOnSubscribe source) 方法的時(shí)候,最終會(huì)返回 ObservableCreate 實(shí)例。因此,我們只需要關(guān)注 ObservableCreate 的 subscribeActual 方法。
protected void subscribeActual(Observer<? super T> observer) {
        // CreateEmitter 是 ObservableCreate 的一個(gè)靜態(tài)內(nèi)部類(lèi)
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        observer.onSubscribe(parent);

        try {
            // source 是上游 ObservableOnSubscribe 的引用
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }

繼續(xù)看ObservableCreate的subscribeActual方法,在執(zhí)行observer.onSubscribe 方法的時(shí)候,會(huì)將parent對(duì)象作為方法參數(shù)暴露出去,parent即是CreateEmitter,可以通過(guò)它的dispose方法取消訂閱關(guān)系。
接著在調(diào)用source.subscribe(parent)的時(shí)候,會(huì)先調(diào)用ObservableOnSubscribe 的 subscribe 方法。
因此,我們可以得出,調(diào)用的順序是:
Observable.subscrible -> Observable.subscribleActual -> Observable.subscribleActual -> observer.onSubscribe -> ObservableOnSubscribe.subscribe(emitter)
emitter是CreateEmitter的實(shí)例,包裝了observe,調(diào)用emitter的方法,就會(huì)調(diào)用observe的 onNext 、onComolete/onError方法。

以上是RxJava基本原理,Observable 和 Observer 通過(guò) subscribe() 方法實(shí)現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時(shí)候發(fā)出事件來(lái)通知 Observer,并且回調(diào) Observer 的相應(yīng)的方法。

2.5 RxJava 線(xiàn)程切換

Observable通過(guò)subscribeOn方法來(lái)指定線(xiàn)程

public final Observable<T> subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
    }

通過(guò)代碼可以看出,先對(duì)scheduler進(jìn)行判空,然后用ObservableSubscribeOn 將scheduler 包裝起來(lái),接下來(lái)研究看看ObservableSubscribeOn這個(gè)類(lèi)的源碼。

final Scheduler scheduler;

    public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
        super(source);
        this.scheduler = scheduler;
    }

    @Override
    public void subscribeActual(final Observer<? super T> observer) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);

        observer.onSubscribe(parent);

        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

首先先來(lái)看他的構(gòu)造函數(shù) ,有兩個(gè)參數(shù) source ,scheduler。

  • source 代表上游的引用,是 Observable 的一個(gè)實(shí)例
  • scheduler 調(diào)度器可以通過(guò) Schedulers.newThread() 或者 Schedulers.io() 創(chuàng)建相應(yīng)的實(shí)例。
    RxJava 可用的調(diào)度器大概有下面幾種,根據(jù)需求選擇:
圖片.png

我們主要看下這個(gè)方法

parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));

SubscribeTask 這個(gè)類(lèi),他是 ObservableSubscribeOn 的一個(gè)非靜態(tài)內(nèi)部類(lèi),可以看到 其實(shí)也比較簡(jiǎn)單,他實(shí)現(xiàn)了 Runnable 接口,并且持有 parent 引用。

 final class SubscribeTask implements Runnable {
        private final SubscribeOnObserver<T> parent;

        SubscribeTask(SubscribeOnObserver<T> parent) {
            this.parent = parent;
        }

        @Override
        public void run() {
            source.subscribe(parent);
        }
    }

在 run 方法中,通過(guò) source.subscribe(parent) 建立聯(lián)系。因而,當(dāng)我們的 SubscribeTask 的 run 方法運(yùn)行在哪個(gè)線(xiàn)程,相應(yīng)的 observer 的 subscribe 方法就運(yùn)行在哪個(gè)線(xiàn)程。

接下來(lái)再看看scheduleDirect的實(shí)現(xiàn)

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;
    }

這個(gè)方法主要是將task包裝成DisposeTask,然后通過(guò)Worker進(jìn)行調(diào)度。再看看Worker 是在做啥。
Scheduler我們以NewThreadScheduler為例子

public final class NewThreadScheduler extends Scheduler {

    final ThreadFactory threadFactory;

    private static final String THREAD_NAME_PREFIX = "RxNewThreadScheduler";
    /**
     * daizy -- 線(xiàn)程池
     */
    private static final RxThreadFactory THREAD_FACTORY;

    /** The name of the system property for setting the thread priority for this Scheduler. */
    private static final String KEY_NEWTHREAD_PRIORITY = "rx2.newthread-priority";

    static {
        int priority = Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY,
                Integer.getInteger(KEY_NEWTHREAD_PRIORITY, Thread.NORM_PRIORITY)));

        THREAD_FACTORY = new RxThreadFactory(THREAD_NAME_PREFIX, priority);
    }

    public NewThreadScheduler() {
        this(THREAD_FACTORY);
    }

    public NewThreadScheduler(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }


    @NonNull
    @Override
    public Worker createWorker() {
        // 通過(guò)線(xiàn)程池來(lái)調(diào)度
        return new NewThreadWorker(threadFactory);
    }
}

通過(guò)代碼可以看出來(lái),Worker里頭封裝了線(xiàn)程池,所以RxJava的線(xiàn)程切換,也是基于線(xiàn)程池來(lái)處理。

回過(guò)來(lái)看DisposeTask

static final class DisposeTask implements Disposable, Runnable, SchedulerRunnableIntrospection {

        @NonNull
        final Runnable decoratedRun;

        @NonNull
        final Worker w;

        @Nullable
        Thread runner;

        DisposeTask(@NonNull Runnable decoratedRun, @NonNull Worker w) {
            this.decoratedRun = decoratedRun;
            this.w = w;
        }

        @Override
        public void run() {
            runner = Thread.currentThread();
            try {
                decoratedRun.run();
            } finally {
                dispose();
                runner = null;
            }
        }

        @Override
        public void dispose() {
            if (runner == Thread.currentThread() && w instanceof NewThreadWorker) {
                ((NewThreadWorker)w).shutdown();
            } else {
                w.dispose();
            }
        }

        @Override
        public boolean isDisposed() {
            return w.isDisposed();
        }

        @Override
        public Runnable getWrappedRunnable() {
            return this.decoratedRun;
        }
    }

DisposeTask 實(shí)現(xiàn)了 Disposable,Runnable ,SchedulerRunnableIntrospection 接口,Disposable 接口主要是用來(lái)取消訂閱關(guān)系的 Disposable。

從上面的分析,可以得出Observable.subscribeOn方法,控制Observable的執(zhí)行線(xiàn)程是通過(guò)將 Observable.subscribe(Observer) 的操作放在了指定線(xiàn)程中,當(dāng)我們調(diào)用 subcribe 的時(shí)候,它的過(guò)程是從下往上的,即下面的 Observable 調(diào)用上面的 Observable。

用流程圖描述如下:


圖片.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容

  • 響應(yīng)式編程簡(jiǎn)介 響應(yīng)式編程是一種基于異步數(shù)據(jù)流概念的編程模式。數(shù)據(jù)流就像一條河:它可以被觀(guān)測(cè),被過(guò)濾,被操作,或者...
    說(shuō)碼解字閱讀 3,085評(píng)論 0 5
  • 轉(zhuǎn)一篇文章 原地址:http://gank.io/post/560e15be2dca930e00da1083 前言...
    jack_hong閱讀 933評(píng)論 0 2
  • 一、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    無(wú)求_95dd閱讀 3,152評(píng)論 0 21
  • 注:只包含標(biāo)準(zhǔn)包中的操作符,用于個(gè)人學(xué)習(xí)及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 2,212評(píng)論 2 8
  • 一、Retrofit詳解 ·Retrofit的官網(wǎng)地址為 : http://square.github.io/re...
    余生_d630閱讀 1,890評(píng)論 0 5