Carson帶你學Android:RxJava變換操作符

前言

Rxjava,由于其基于事件流的鏈式調用、邏輯簡潔 & 使用簡單的特點,深受各大 Android開發者的歡迎。

如果還不了解 RxJava,請看文章:Android:這是一篇 清晰 & 易懂的Rxjava 入門教程

  • RxJava如此受歡迎的原因,在于其提供了豐富 & 功能強大的操作符,幾乎能完成所有的功能需求
  • 今天,我將為大家詳細介紹RxJava操作符中最常用的變換操作符,并附帶 Retrofit 結合 RxJava的實例Demo教學,希望你們會喜歡。

Carson帶你學RxJava系列文章,包括 原理、操作符、應用場景、背壓等等,請關注看文章:Android:這是一份全面 & 詳細的RxJava學習指南


目錄

示意圖

1. 作用

  • 對事件序列中的事件 / 整個事件序列 進行加工處理(即變換),使得其轉變成不同的事件 / 整個事件序列
  • 具體原理如下
示意圖

2. 類型

  • RxJava中常見的變換操作符如下:

    示意圖

  • 下面,我將對每種操作符進行詳細介紹

注:本文只講解RxJava2在開發過程中常用的變換操作符


3. 應用場景 & 對應操作符 介紹

  • 下面,我將對 RxJava2 中的變換操作符進行逐個講解
  • 注:在使用RxJava 2操作符前,記得在項目的Gradle中添加依賴:
dependencies {
      compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
      compile 'io.reactivex.rxjava2:rxjava:2.0.7'
      // 注:RxJava2 與 RxJava1 不能共存,即依賴不能同時存在
}

3.1 Map()

  • 作用
    對 被觀察者發送的每1個事件都通過 指定的函數 處理,從而變換成另外一種事件

即, 將被觀察者發送的事件轉換為任意的類型事件。

  • 原理
示意圖
  • 應用場景
    數據類型轉換
  • 具體使用
    下面以將 使用Map() 將事件的參數從 整型 變換成 字符串類型 為例子說明
示意圖
 // 采用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 ;
            }
        }).subscribe(new Consumer<String>() {

            // 3. 觀察者接收事件時,是接收到變換后的事件 = 字符串類型
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });

  • 測試結果
示意圖

從上面可以看出,map() 將參數中的 Integer 類型對象轉換成一個 String類型 對象后返回

同時,事件的參數類型也由 Integer 類型變成了 String 類型


3.2 FlatMap()

  • 作用:將被觀察者發送的事件序列進行 拆分 & 單獨轉換,再合并成一個新的事件序列,最后再進行發送

  • 原理

  1. 為事件序列中每個事件都創建一個 Observable 對象;
  2. 將對每個 原始事件 轉換后的 新事件 都放入到對應 Observable對象;
  3. 將新建的每個Observable 都合并到一個 新建的、總的Observable 對象;
  4. 新建的、總的Observable 對象 將 新合并的事件序列 發送給觀察者(Observer
示意圖
  • 應用場景
    無序的將被觀察者發送的整個事件序列進行變換

  • 具體使用

// 采用RxJava基于事件流的鏈式操作
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }

            // 采用flatMap()變換操作符
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
                    // 通過flatMap中將被觀察者生產的事件序列先進行拆分,再將每個事件轉換為一個新的發送三個String事件
                    // 最終合并,再發送給被觀察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });
  • 測試結果


    示意圖

注:新合并生成的事件序列順序是無序的,即 與舊序列發送事件的順序無關

3.3 ConcatMap()

  • 作用:類似FlatMap()操作符

  • FlatMap()的 區別在于:拆分 & 重新合并生成的事件序列 的順序 = 被觀察者舊序列生產的順序

  • 原理

示意圖
  • 應用場景
    有序的將被觀察者發送的整個事件序列進行變換

  • 具體使用

// 采用RxJava基于事件流的鏈式操作
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }

            // 采用concatMap()變換操作符
        }).concatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
                    // 通過concatMap中將被觀察者生產的事件序列先進行拆分,再將每個事件轉換為一個新的發送三個String事件
                    // 最終合并,再發送給被觀察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });
  • 測試結果


    示意圖

注:新合并生成的事件序列順序是有序的,即 嚴格按照舊序列發送事件的順序


3.4 Buffer()

  • 作用
    定期從 被觀察者(Obervable)需要發送的事件中 獲取一定數量的事件 & 放到緩存區中,最終發送

  • 原理

示意圖
  • 應用場景
    緩存被觀察者發送的事件
  • 具體使用
    那么,Buffer()每次是獲取多少個事件放到緩存區中的呢?下面我將通過一個例子來說明
// 被觀察者 需要發送5個數字
        Observable.just(1, 2, 3, 4, 5)
                .buffer(3, 1) // 設置緩存區大小 & 步長
                                    // 緩存區大小 = 每次從被觀察者中獲取的事件數量
                                    // 步長 = 每次獲取新事件的數量
                .subscribe(new Observer<List<Integer>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(List<Integer> stringList) {
                        //
                        Log.d(TAG, " 緩存區里的事件數量 = " +  stringList.size());
                        for (Integer value : stringList) {
                            Log.d(TAG, " 事件 = " + value);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "對Error事件作出響應" );
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "對Complete事件作出響應");
                    }
                });
  • 測試結果
示意圖
  • 過程解釋

下面,我將通過一個圖來解釋Buffer()原理 & 整個例子的結果

示意圖

至此,關于RxJava2中主要的變換操作符已經講解完畢


4. 實際開發需求案例

  • 變換操作符的主要開發需求場景 = 嵌套回調(Callback hell
  • 下面,我將采用一個實際應用場景實例來講解嵌套回調(Callback hell

具體請看文章Android RxJava 實際應用案例講解:網絡請求嵌套回調


5. Demo地址

上述所有的Demo源代碼都存放在:Carson_Ho的Github地址:RxJava2_變換操作符

喜歡的麻煩點個star


6. 總結

  • 下面,我將用一張圖總結 RxJava2 中常用的變換操作符
示意圖
  • Carson帶你學RxJava系列文章:

入門
Carson帶你學Android:這是一篇清晰易懂的Rxjava入門教程
Carson帶你學Android:面向初學者的RxJava使用指南
Carson帶你學Android:RxJava2.0到底更新了什么?
原理
Carson帶你學Android:圖文解析RxJava原理
Carson帶你學Android:手把手帶你源碼分析RxJava
使用教程:操作符
Carson帶你學Android:RxJava操作符教程
Carson帶你學Android:RxJava創建操作符
Carson帶你學Android:RxJava功能性操作符
Carson帶你學Android:RxJava過濾操作符
Carson帶你學Android:RxJava組合/合并操作符
Carson帶你學Android:RxJava變換操作符
Carson帶你學Android:RxJava條件/布爾操作符
實戰
Carson帶你學Android:什么時候應該使用Rxjava?(開發場景匯總)
Carson帶你學Android:RxJava線程控制(含實例講解)
Carson帶你學Android:圖文詳解RxJava背壓策略
Carson帶你學Android:RxJava、Retrofit聯合使用匯總(含實例教程)
Carson帶你學Android:優雅實現網絡請求嵌套回調
Carson帶你學Android:網絡請求輪詢(有條件)
Carson帶你學Android:網絡請求輪詢(無條件)
Carson帶你學Android:網絡請求出錯重連(結合Retrofit)
Carson帶你學Android:合并數據源
Carson帶你學Android:聯想搜索優化
Carson帶你學Android:功能防抖
Carson帶你學Android:從磁盤/內存緩存中獲取緩存數據
Carson帶你學Android:聯合判斷


歡迎關注Carson_Ho的簡書

不定期分享關于安卓開發的干貨,追求短、平、快,但卻不缺深度


請點贊!因為你的鼓勵是我寫作的最大動力!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容