RxJava2操作符之flatMap與concatMap

概述

在前文RxJava2操作符之map中記錄了map的使用方法及場景,而日常開發中除了map,flatMap以及concatMap使用的也比較多,那這篇文章就記錄一下這兩個操作符的情況。
RxJava2操作符之map中介紹了一些基礎知識以及學習方法,強烈建議先大體瀏覽一下。

flatMap

使用場景

第一:比較典型的就是可以使用flatMap解決嵌套回調的問題,例如我們有兩個API,A和B,B的調用需要A的返回結果作爲參數,如果以回調的方式來完成的話,我們需要在A的callback中發起B的調用,然後在B的callback中處理返回結果。
第二:凡是需要map,而變換後需要一個Observable的場景下均可以考慮。

使用說明

官方解釋:

Returns an Observable that emits items based on applying a function that you supply to each item emitted by the source ObservableSource, where that function returns an ObservableSource, and then merging those resulting, ObservableSources and emitting the results of this merger.
前半部分與map操作符一致,會對原始發射的每個數據進行轉換,但是與map不同的是flatMap對每一個數據項轉換後的結果是一個Observable。這些轉換後得到的Observable會被合併在一起後由一個統一的Observable分別發射這個集合體的事件。

解釋過於抽象,請看下圖:
在這裏插入圖片描述
上面3個圓圈經過中間的flatMap變成了下面的6個菱形。爲什麼是6個呢,因爲圖中的flatMap將1個圓圈變成2個菱形。如果faltMap的規則是將1個圓圈變爲1個菱形,那麼最終就是3個菱形了,這個由我們使用者決定。還有值得注意的一點就是,下面的綠色菱形和藍色凌的順序交叉了,而不是按照2個紅色,2個綠色,2個藍色的順序來的。這說明flatMap變換後發射數據的順序是不可預測的,這一點要注意。

 Observable.range(1,3)
         .flatMap(new Function<Integer, ObservableSource<String>>()
         {
             @Override
             public ObservableSource<String> apply(final Integer integer) throws Exception
             {
                 return Observable.create(new ObservableOnSubscribe<String>()
                 {
                     @Override
                     public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                         emitter.onNext(String.format("第%s個數據的第1個轉換",integer));
                         emitter.onNext(String.format("第%s個數據的第2個轉換",integer));
                         emitter.onComplete();
                     }
                 }).subscribeOn(Schedulers.newThread());
             }
         }).subscribeOn(Schedulers.computation())
         .observeOn(AndroidSchedulers.mainThread())
         .subscribe(new Consumer<String>() {
             @Override
             public void accept(String s) throws Exception  {
                 Log.d("FlatMap",s);
             }
         });

上面的代碼是將1,2,3三個數據源分別使用flatMap作了變換, 得到3個Observable,而在每一個Observable中又分別發射了兩個變換後的數據,那總共就是6條數據。

輸出結果:
第一次執行:

2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1個數據的第1個轉換
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2個數據的第1個轉換
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2個數據的第2個轉換
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3個數據的第1個轉換
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3個數據的第2個轉換
2018-10-21 19:06:25.066 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1個數據的第2個轉換

第二次執行:

2018-10-21 19:07:15.185 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3個數據的第1個轉換
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第3個數據的第2個轉換
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1個數據的第1個轉換
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第1個數據的第2個轉換
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2個數據的第1個轉換
2018-10-21 19:07:15.186 8732-8732/top.ss007.rxjavaoperatorsdemo D/FlatMap: 第2個數據的第2個轉換

從輸出結果可以看到,6個數據項到達觀察端的順序是不固定的,由每個的發射順序和執行時間一起決定。發射的早而耗時又少的肯定是首先到達,那些發射晚而耗時又長的肯定是最後到達。

那麼遇到需要按照發射順序而獲得到達順序時怎麼辦呢?conactMap就閃亮登場了!

conactMap

官方解釋

Returns a new Observable that emits items resulting from applying a function that you supply to each item emitted by the source ObservableSource, where that function returns an ObservableSource, and then emitting the items that result from concatenating those resulting ObservableSources.

在這裏插入圖片描述
從上圖可知,conactMap 與flatMap唯一的區別就是接收的數據是與發射數據的順序一致。

將上面代碼中的flatMap換爲conactMap,然後看一下輸出結果:

Observable.range(1,3)
        .concatMap(new Function<Integer, ObservableSource<String>>() {
            ...
        }).subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<String>()  {
            @Override
            public void accept(String s) throws Exception {
                     Log.d("ConcatMap",s);
            }
        });

輸出結果:
第一次輸出:

2018-10-21 19:22:13.449 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1個數據的第2個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2個數據的第2個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3個數據的第2個轉換

第二次輸出:

2018-10-21 19:22:13.449 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第1個數據的第2個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第2個數據的第2個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3個數據的第1個轉換
2018-10-21 19:22:13.450 8732-8732/top.ss007.rxjavaoperatorsdemo D/ConcatMap: 第3個數據的第2個轉換

可見多次執行後輸出結果是穩定的。

總結

Talk is cheap,show me the picture, 真是一圖勝前言啊!希望大家再遇到不熟悉的rxjava2的操作符,先看一下那個配圖。

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