Rxjava 2.x 原始碼系列 - 變換操作符 Map(上)

stormjun發表於2019-04-26

Rxjava 2.x 原始碼系列 - 基礎框架分析

Rxjava 2.x 原始碼系列 - 執行緒切換 (上)

Rxjava 2.x 原始碼系列 - 執行緒切換 (下)

Rxjava 2.x 原始碼系列 - 變換操作符 Map(上)

前言

在前幾篇部落格中,我們介紹了 Rxjava Observable 與 Observer 之間是如何訂閱與取消訂閱的,以及 Rxjava 是如何控制 subsribe 執行緒和 observer 的回撥執行緒的。

今天,讓我們一起來看一下 Rxjava 中另外一個比較重要的功能,操作符變化功能


基礎知識

常用的變換操作符

操作符 作用
map 對映,將一種型別的資料流/Observable對映為另外一種型別的資料流/Observable
cast 強轉 傳入一個class,對Observable的型別進行強轉.
flatMap 平鋪對映,從資料流的每個資料元素中對映出多個資料,並將這些資料依次發射。(注意是無序的)
concatMap concatMap 與 flatMap 的功能非常類似,只不過傳送的資料是有序的
buffer 快取/打包 按照一定規則從Observable收集一些資料到一個集合,然後把這些資料作為集合打包發射。
groupby 分組,將原來的Observable分拆為Observable集合,將原始Observable發射的資料按Key分組,每一個Observable發射一組不同的資料
to... 將資料流中的物件轉換為List/SortedList/Map/MultiMap集合物件,並打包發射
timeInterval 將每個資料都換為包含本次資料和離上次發射資料時間間隔的物件併發射
timestamp 將每個資料都轉換為包含本次資料和發射資料時的時間戳的物件併發射

從 Demo 說起

接下來,我們一起來看一下一個 demo,我們通過 map 操作符將 Integer 轉化為 String。

// 採用RxJava基於事件流的鏈式操作
Observable.create(new ObservableOnSubscribe<Integer>() {

    // 1. 被觀察者傳送事件 = 引數為整型 = 1、2、3
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        emitter.onNext(1);
        emitter.onNext(2);
        emitter.onNext(3);

    }
    // 2. 使用Map變換操作符中的Function函式對被觀察者傳送的事件進行統一變換:整型變換成字串型別
}).map(new Function<Integer, String>() {
    @Override
    public String apply(Integer integer) throws Exception {
        return "使用 Map變換操作符 將事件" + integer +"的引數從 整型"+integer + " 變換成 字串型別" + integer ;
    }
    // 3. 觀察者接收事件時,是接收到變換後的事件 = 字串型別
}).subscribe(new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
        
    }

    @Override
    public void onNext(String s) {
        Log.d(TAG, s);
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});


複製程式碼

輸出結果

使用 Map變換操作符 將事件1的引數從 整型1 變換成 字串型別1
使用 Map變換操作符 將事件2的引數從 整型2 變換成 字串型別2
使用 Map變換操作符 將事件3的引數從 整型3 變換成 字串型別3

複製程式碼

map 原始碼分析

  • 借鑑前面幾篇部落格的分析,我們先來看一下 Observable 的 map 方法,它的套路跟 create 方法的套路也是相似的,判空是否為 null,為 null 丟擲異常。
  • 接著,用一個包裝類包裝當前的 Observable 例項,只不過這個包裝類是 ObservableMap。在 ObsevableMap 裡面持有上游 observable 例項的引用,這個是典型的裝飾者模式. 關於裝飾者模式,可以參考我的這一篇部落格。裝飾者模式及其應用
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
    ObjectHelper.requireNonNull(mapper, "mapper is null");
    return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}


複製程式碼

接下來,我們一起來看一下 ObservableMap。

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
    final Function<? super T, ? extends U> function;

    public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
        super(source);
        this.function = function;
    }

    @Override
    public void subscribeActual(Observer<? super U> t) {
        source.subscribe(new MapObserver<T, U>(t, function));
    }
}
複製程式碼

在前面部落格中,我們已經說到,當我們呼叫 observable.subscribe(observer) 的時候,程式碼呼叫邏輯是這樣的。

在 observable 的 subscribeActual 方法中

  • 如果有上游的話,會呼叫上游的 subscribe 方法(即 source.subscribe() 方法),而在 subscribe 方法中,又會呼叫當前 observable 的 subcribeActual 方法
  • 如果沒有上游的話,會直接呼叫當前 Observable 的 subscirbe 方法,並呼叫 observable 的 onSuscribe 方法

observable 的 subscribe 流程圖

在 ObservableMap 的 subscribeActual 方法裡面,MapObserver 類對 Observer 進行包裝,又是這樣的套路,裝飾者模式。

static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
    final Function<? super T, ? extends U> mapper;

    MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
        super(actual);
        this.mapper = mapper;
    }

    @Override
    public void onNext(T t) {
       // 1 判斷是否 done,如果已經 done ,直接返回
        if (done) {
            return;
        }

        if (sourceMode != NONE) {
            actual.onNext(null);
            return;
        }

        U v;
      
        try {
            // 2 呼叫 mapper.apply(t) ,進行相應的轉化
            v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
        } catch (Throwable ex) {
            fail(ex);
            return;
        }
        // 3 呼叫下游的 onNext 方法,並將 V 暴露出去
        actual.onNext(v);
    }
    
    
    ----

}
複製程式碼

首先看他的構造方法,有兩個引數, actual,mapper。 actual 代表下游的 Observer,mapper 為傳入的 Function。

接著我們來看下 onNext 方法

  1. 判斷是否 done,如果已經 done ,直接返回
  2. 呼叫 mapper.apply(t) ,進行相應的轉化
  3. 呼叫下游的 onNext 方法,並將 V 暴露出去

這樣就完成了操作符的操作功能

總結

OK,我們在回到上面的 demo,來整理一下他的流程

Rxjava 2.x 原始碼系列 - 變換操作符 Map(上)

當我們呼叫 observable.subscribe(observer) 的時候

  • 會促發第二個 Observable 的 subscribeAtActual 方法,在該方法中,又會呼叫上游 Observable 的 subscribe 方法,即第一個 Observable 的 subscribe 方法
  • 在第一個 Observable 的 subscribe 方法裡面,又會呼叫當前 Observable 的 subscribeAtActual 方法,會呼叫 observer.onSubscribe(parent) 方法,並呼叫 source.subscribe(parent) 將我們的 observer 的包裝類 parent 暴露出去
  • 當我們在我們建立的 ObservableOnSubscribe 的 subscribe 方法中,呼叫 emitter 的 onNext 方法的時候,這個時候會呼叫到我們的 MapObserver 的 onNext 方法
  • 在 MapObserver 的 onNext 方法,有會呼叫到下游 Observer 的 onNext 方法,進而呼叫我們外部的 observer 的 onNext 方法

小結

  • map 的操作過程跟之前的執行緒切換的實現原理基本一樣,通過在中間使用裝飾者模式插入一箇中間的 Observable 和 Observer,你可以想象為代理。
  • 代理 Observable 做的事就是接收下游 Obsever 的訂閱事件,然後通過代理 Obsever 訂閱上游 Observer,然後在上游 Observer 下發資料給代理 Observer 時,通過先呼叫 mapper.apply 轉換回撥函式獲得轉換後的資料,然後下發給下游 Obsever。

Android 技術人

掃一掃,歡迎關注我的公眾號。如果你有好的文章,也歡迎你的投稿。

相關文章