RxJava系列3(轉換操作符)

剛剛開通了微信公眾號:BaronTalk,之前專欄上的文章也陸續(xù)完成了搬遷。后續(xù)會持續(xù)保質保量的輸出,覺得我的文章還有值得一讀那就關注一波吧!?。?:-)


前面兩篇文章中我們介紹了RxJava的一些基本概念和RxJava最簡單的用法。從這一章開始,我們開始聊聊RxJava中的操作符Operators,RxJava中的操作符主要分成了三類:

  1. 轉換類操作符(map flatMap concatMap flatMapIterable switchMap scan groupBy ...);
  2. 過濾類操作符(fileter take takeLast takeUntil distinct distinctUntilChanged skip skipLast ...);
  3. 組合類操作符(merge zip join combineLatest and/when/then switch startSwitch ...)。

這一章我們主要講講轉換類操作符。所有這些Operators都作用于一個可觀測序列,然后變換它發(fā)射的值,最后用一種新的形式返回它們。概念實在是不好理解,下面我們結合實際的例子一一介紹。

map

map()函數(shù)接受一個Func1類型的參數(shù)(就像這樣map(Func1<? super T, ? extends R> func)),然后吧這個Func1應用到每一個由Observable發(fā)射的值上,將發(fā)射的只轉換為我們期望的值。這種狗屁定義我相信你也聽不懂,我們來看一下官方給出的原理圖:

MapOperator

假設我們需要將一組數(shù)字裝換成字符串,我們可以通過map這樣實現(xiàn):

Observable.just(1, 2, 3, 4, 5)
        .map(new Func1<Integer, String>() {
            @Override
            public String call(Integer i) {
                return "This is " + i;
            }
        }).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                System.out.println(s);
            }
        });

Func1構造函數(shù)中的兩個參數(shù)分別是Observable發(fā)射值當前的類型和map轉換后的類型,上面這個例子中發(fā)射值當前的類型是Integer,轉換后的類型是String。

flatMap

flatMap()函數(shù)同樣也是做轉換的,但是作用卻不一樣。flatMap不開好理解,我們直接看例子(我們公司是個房產(chǎn)平臺,那我就拿房子舉例):假設我們有一組小區(qū)Community[] communites,現(xiàn)在我們要輸出每個小區(qū)的名字;我們可以這樣實現(xiàn):

Observable.from(communities)
        .map(new Func1<Community, String>() {
            @Override
            public String call(Community community) {
                return community.name;
            }
        })
        .subscribe(new Action1<String>() {
            @Override
            public void call(String name) {
                System.out.println("Community name : " + name);
            }
        });

現(xiàn)在我們需求有變化,需要打印出每個小區(qū)下面所有房子的價格。于是我可以這樣實現(xiàn):

Community[] communities = {};
Observable.from(communities)
        .subscribe(new Action1<Community>() {
            @Override
            public void call(Community community) {
                for (House house : community.houses) {
                    System.out.println("House price : " + house.price);
                }
            }
        });

如果我不想在Subscriber中使用for循環(huán),而是希望Subscriber中直接傳入單個的House對象呢(這對于代碼復用很重要)?用map()顯然是不行的,因為map()是一對一的轉化,而我現(xiàn)在的要求是一對多的轉化。那么我們可以使用flatMap()把一個Community轉化成多個House。

Observable.from(communities)
        .flatMap(new Func1<Community, Observable<House>>() {
            @Override
            public Observable<House> call(Community community) {
                return Observable.from(community.houses);
            }
        })
        .subscribe(new Action1<House>() {
            @Override
            public void call(House house) {
                System.out.println("House price : " + house.price);
            }
        });

從前面的例子中你坑定發(fā)現(xiàn)了,flatMap()和map()都是把傳入的參數(shù)轉化之后返回另一個對象。但和map()不同的是,flatMap()中返回的是Observable對象,并且這個Observable對象并不是被直接發(fā)送到 Subscriber的回調方法中。

flatMap()的原理是這樣的:

  1. 將傳入的事件對象裝換成一個Observable對象;
  2. 這是不會直接發(fā)送這個Observable, 而是將這個Observable激活讓它自己開始發(fā)送事件;
  3. 每一個創(chuàng)建出來的Observable發(fā)送的事件,都被匯入同一個Observable,這個Observable負責將這些事件統(tǒng)一交給Subscriber的回調方法。

這三個步驟,把事件拆成了兩級,通過一組新創(chuàng)建的Observable將初始的對象『鋪平』之后通過統(tǒng)一路徑分發(fā)了下去。而這個『鋪平』就是flatMap()所謂的flat。

最后我們來看看flatMap的原理圖:

FlatMapOperator

concatMap

concatMap()解決了flatMap()的交叉問題,它能夠把發(fā)射的值連續(xù)在一起,就像這樣:

ConcatMapOperator

flatMapIterable

flatMapIterable()flatMap()幾乎是一樣的,不同的是flatMapIterable()它轉化的多個Observable是使用Iterable作為源數(shù)據(jù)的。

FlatMapIterableOperator

Observable.from(communities)
        .flatMapIterable(new Func1<Community, Iterable<House>>() {
            @Override
            public Iterable<House> call(Community community) {
                return community.houses;
            }
        })
        .subscribe(new Action1<House>() {

            @Override
            public void call(House house) {

            }
        });

switchMap

switchMap()flatMap()很像,除了一點:每當源Observable發(fā)射一個新的數(shù)據(jù)項(Observable)時,它將取消訂閱并停止監(jiān)視之前那個數(shù)據(jù)項產(chǎn)生的Observable,并開始監(jiān)視當前發(fā)射的這一個。

SwitchMapOperator

scan

scan()對一個序列的數(shù)據(jù)應用一個函數(shù),并將這個函數(shù)的結果發(fā)射出去作為下個數(shù)據(jù)應用合格函數(shù)時的第一個參數(shù)使用。

ScanOperator

我們來看個簡單的例子:

Observable.just(1, 2, 3, 4, 5)
        .scan(new Func2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        }).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
        System.out.print(integer+“ ”);
    }
});

輸出結果為:1 3 6 10 15

groupBy

groupBy()將原始Observable發(fā)射的數(shù)據(jù)按照key來拆分成一些小的Observable,然后這些小Observable分別發(fā)射其所包含的的數(shù)據(jù),和SQL中的groupBy類似。實際使用中,我們需要提供一個生成key的規(guī)則(也就是Func1中的call方法),所有key相同的數(shù)據(jù)會包含在同一個小的Observable中。另外我們還可以提供一個函數(shù)來對這些數(shù)據(jù)進行轉化,有點類似于集成了flatMap。

GroupByOperator

單純的文字描述和圖片解釋可能難以理解,我們來看個例子:假設我現(xiàn)在有一組房源List<House> houses,每套房子都屬于某一個小區(qū),現(xiàn)在我們需要根據(jù)小區(qū)名來對房源進行分類,然后依次將房源信息輸出。

List<House> houses = new ArrayList<>();
houses.add(new House("中糧·海景壹號", "中糧海景壹號新出大平層!總價4500W起"));
houses.add(new House("竹園新村", "滿五唯一,黃金地段"));
houses.add(new House("中糧·海景壹號", "毗鄰湯臣一品"));
houses.add(new House("竹園新村", "頂層戶型,兩室一廳"));
houses.add(new House("中糧·海景壹號", "南北通透,豪華五房"));
Observable<GroupedObservable<String, House>> groupByCommunityNameObservable = Observable.from(houses)
        .groupBy(new Func1<House, String>() {

            @Override
            public String call(House house) {
                return house.communityName;
            }
        });

通過上面的代碼我們創(chuàng)建了一個新的Observable:groupByCommunityNameObservable,它將會發(fā)送一個帶有GroupedObservable的序列(也就是指發(fā)送的數(shù)據(jù)項的類型為GroupedObservable)。GroupedObservable是一個特殊的Observable,它基于一個分組的key,在這個例子中的key就是小區(qū)名。現(xiàn)在我們需要將分類后的房源依次輸出:

Observable.concat(groupByCommunityNameObservable)
        .subscribe(new Action1<House>() {
            @Override
            public void call(House house) {
                System.out.println("小區(qū):"+house.communityName+"; 房源描述:"+house.desc);
            }
        });

執(zhí)行結果:

小區(qū):中糧·海景壹號; 房源描述:中糧海景壹號新出大平層!總價4500W起
小區(qū):中糧·海景壹號; 房源描述:毗鄰湯臣一品
小區(qū):中糧·海景壹號; 房源描述:南北通透,豪華五房
小區(qū):竹園新村; 房源描述:滿五唯一,黃金地段
小區(qū):竹園新村; 房源描述:頂層戶型,兩室一廳

轉換類的操作符就先介紹到這,后續(xù)還會繼續(xù)介紹組合、過濾類的操作符及源碼分析,敬請期待!

如果你喜歡我的文章,就關注下我的公眾號 BaronTalk 、 知乎專欄 或者在 GitHub 上添個 Star 吧!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應式編程作為結合使用的,對什么是操作、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,994評論 0 10
  • 注:只包含標準包中的操作符,用于個人學習及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 2,377評論 2 8
  • 作者: maplejaw本篇只解析標準包中的操作符。對于擴展包,由于使用率較低,如有需求,請讀者自行查閱文檔。 創(chuàng)...
    maplejaw_閱讀 46,219評論 8 93
  • 前言 按照官方的分類,操作符大致分為以下幾種: Creating Observables(Observable的創(chuàng)...
    小玉1991閱讀 1,126評論 0 1
  • 創(chuàng)建操作 用于創(chuàng)建Observable的操作符Create通過調用觀察者的方法從頭創(chuàng)建一個ObservableEm...
    rkua閱讀 1,958評論 0 1

友情鏈接更多精彩內容