Carson帶你學(xué)Android:RxJava變換操作符

前言

Rxjava玄叠,由于其基于事件流的鏈?zhǔn)秸{(diào)用古徒、邏輯簡潔 & 使用簡單的特點砰识,深受各大 Android開發(fā)者的歡迎撑刺。

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

  • RxJava如此受歡迎的原因述呐,在于其提供了豐富 & 功能強(qiáng)大的操作符寺惫,幾乎能完成所有的功能需求
  • 今天疹吃,我將為大家詳細(xì)介紹RxJava操作符中最常用的變換操作符,并附帶 Retrofit 結(jié)合 RxJava的實例Demo教學(xué)西雀,希望你們會喜歡萨驶。

Carson帶你學(xué)RxJava系列文章,包括 原理蒋搜、操作符篡撵、應(yīng)用場景、背壓等等豆挽,請關(guān)注看文章:Android:這是一份全面 & 詳細(xì)的RxJava學(xué)習(xí)指南


目錄

示意圖

1. 作用

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

2. 類型

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

    示意圖

  • 下面,我將對每種操作符進(jìn)行詳細(xì)介紹

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


3. 應(yīng)用場景 & 對應(yīng)操作符 介紹

  • 下面帮哈,我將對 RxJava2 中的變換操作符進(jìn)行逐個講解
  • 注:在使用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()

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

即咖刃, 將被觀察者發(fā)送的事件轉(zhuǎn)換為任意的類型事件。

  • 原理
示意圖
  • 應(yīng)用場景
    數(shù)據(jù)類型轉(zhuǎn)換
  • 具體使用
    下面以將 使用Map() 將事件的參數(shù)從 整型 變換成 字符串類型 為例子說明
示意圖
 // 采用RxJava基于事件流的鏈?zhǔn)讲僮?        Observable.create(new ObservableOnSubscribe<Integer>() {

            // 1. 被觀察者發(fā)送事件 = 參數(shù)為整型 = 1憾筏、2嚎杨、3
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);

            }
            // 2. 使用Map變換操作符中的Function函數(shù)對被觀察者發(fā)送的事件進(jìn)行統(tǒng)一變換:整型變換成字符串類型
        }).map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "使用 Map變換操作符 將事件" + integer +"的參數(shù)從 整型"+integer + " 變換成 字符串類型" + integer ;
            }
        }).subscribe(new Consumer<String>() {

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

  • 測試結(jié)果
示意圖

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

同時枫浙,事件的參數(shù)類型也由 Integer 類型變成了 String 類型


3.2 FlatMap()

  • 作用:將被觀察者發(fā)送的事件序列進(jìn)行 拆分 & 單獨轉(zhuǎn)換刨肃,再合并成一個新的事件序列,最后再進(jìn)行發(fā)送

  • 原理

  1. 為事件序列中每個事件都創(chuàng)建一個 Observable 對象箩帚;
  2. 將對每個 原始事件 轉(zhuǎn)換后的 新事件 都放入到對應(yīng) Observable對象真友;
  3. 將新建的每個Observable 都合并到一個 新建的、總的Observable 對象紧帕;
  4. 新建的盔然、總的Observable 對象 將 新合并的事件序列 發(fā)送給觀察者(Observer
示意圖
  • 應(yīng)用場景
    無序的將被觀察者發(fā)送的整個事件序列進(jìn)行變換

  • 具體使用

// 采用RxJava基于事件流的鏈?zhǔn)讲僮?        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中將被觀察者生產(chǎn)的事件序列先進(jìn)行拆分,再將每個事件轉(zhuǎn)換為一個新的發(fā)送三個String事件
                    // 最終合并是嗜,再發(fā)送給被觀察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });
  • 測試結(jié)果


    示意圖

注:新合并生成的事件序列順序是無序的愈案,即 與舊序列發(fā)送事件的順序無關(guān)

3.3 ConcatMap()

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

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

  • 原理

示意圖
  • 應(yīng)用場景
    有序的將被觀察者發(fā)送的整個事件序列進(jìn)行變換

  • 具體使用

// 采用RxJava基于事件流的鏈?zhǔn)讲僮?        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中將被觀察者生產(chǎn)的事件序列先進(jìn)行拆分,再將每個事件轉(zhuǎn)換為一個新的發(fā)送三個String事件
                    // 最終合并叠纷,再發(fā)送給被觀察者
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });
  • 測試結(jié)果


    示意圖

注:新合并生成的事件序列順序是有序的刻帚,即 嚴(yán)格按照舊序列發(fā)送事件的順序


3.4 Buffer()

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

  • 原理

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

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

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

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

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

示意圖

至此航厚,關(guān)于RxJava2中主要的變換操作符已經(jīng)講解完畢


4. 實際開發(fā)需求案例

  • 變換操作符的主要開發(fā)需求場景 = 嵌套回調(diào)(Callback hell
  • 下面顷歌,我將采用一個實際應(yīng)用場景實例來講解嵌套回調(diào)(Callback hell

具體請看文章Android RxJava 實際應(yīng)用案例講解:網(wǎng)絡(luò)請求嵌套回調(diào)


5. Demo地址

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

喜歡的麻煩點個star


6. 總結(jié)

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

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


歡迎關(guān)注Carson_Ho的簡書

不定期分享關(guān)于安卓開發(fā)的干貨赦抖,追求短、平辅肾、快队萤,但卻不缺深度


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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市新娜,隨后出現(xiàn)的幾起案子赵辕,更是在濱河造成了極大的恐慌,老刑警劉巖概龄,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件还惠,死亡現(xiàn)場離奇詭異,居然都是意外死亡私杜,警方通過查閱死者的電腦和手機(jī)吸重,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門互拾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嚎幸,你說我怎么就攤上這事〖男桑” “怎么了嫉晶?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長田篇。 經(jīng)常有香客問我替废,道長,這世上最難降的妖魔是什么泊柬? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任椎镣,我火速辦了婚禮,結(jié)果婚禮上兽赁,老公的妹妹穿的比我還像新娘状答。我一直安慰自己,他們只是感情好刀崖,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布惊科。 她就那樣靜靜地躺著,像睡著了一般亮钦。 火紅的嫁衣襯著肌膚如雪馆截。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天蜂莉,我揣著相機(jī)與錄音蜡娶,去河邊找鬼。 笑死映穗,一個胖子當(dāng)著我的面吹牛窖张,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播男公,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼荤堪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枢赔?” 一聲冷哼從身側(cè)響起澄阳,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎踏拜,沒想到半個月后碎赢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡速梗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年肮塞,在試婚紗的時候發(fā)現(xiàn)自己被綠了襟齿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡枕赵,死狀恐怖猜欺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拷窜,我是刑警寧澤开皿,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站篮昧,受9級特大地震影響赋荆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懊昨,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一窄潭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酵颁,春花似錦嫉你、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至其掂,卻和暖如春油挥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背款熬。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工深寥, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贤牛。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓惋鹅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親殉簸。 傳聞我的和親對象是個殘疾皇子闰集,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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