RxJava(十二)combineLatest操作符的高級(jí)使用

RxJava系列文章目錄導(dǎo)讀:

一语婴、RxJava create操作符的用法和源碼分析
二、RxJava map操作符用法詳解
三驶睦、RxJava flatMap操作符用法詳解
四砰左、RxJava concatMap操作符用法詳解
五、RxJava onErrorResumeNext操作符實(shí)現(xiàn)app與服務(wù)器間token機(jī)制
六场航、RxJava retryWhen操作符實(shí)現(xiàn)錯(cuò)誤重試機(jī)制
七缠导、RxJava 使用debounce操作符優(yōu)化app搜索功能
八、RxJava concat操作處理多數(shù)據(jù)源
九溉痢、RxJava zip操作符在Android中的實(shí)際使用場(chǎng)景
十僻造、RxJava switchIfEmpty操作符實(shí)現(xiàn)Android檢查本地緩存邏輯判斷
十一憋他、RxJava defer操作符實(shí)現(xiàn)代碼支持鏈?zhǔn)秸{(diào)用
十二、combineLatest操作符的高級(jí)使用
十三髓削、RxJava導(dǎo)致Fragment Activity內(nèi)存泄漏問題
十四举瑰、interval、takeWhile操作符實(shí)現(xiàn)獲取驗(yàn)證碼功能


combineLatest 操作符用來將多個(gè)Observable發(fā)射的數(shù)據(jù)組裝起來然后在發(fā)射. 通過Func類來組裝多個(gè)Observable發(fā)射的數(shù)據(jù), 等到最后一個(gè)Observable發(fā)射數(shù)據(jù)了, 然后把所有發(fā)射的數(shù)據(jù)交給Fun進(jìn)行組合, 然后把組合后的數(shù)據(jù)發(fā)射出去.

看到網(wǎng)上絕大部分都是用 combineLatest 來做Android表單的校驗(yàn), 總感覺有點(diǎn)大材小用. 如只有表單都只有值了了, 提交按鈕才可用:

    Observable<CharSequence> etFeedbackInputObservable = RxTextView.textChanges(mEditFeedbackInput).skip(1);
    Observable<CharSequence> etFeedbackEmailObservable = RxTextView.textChanges(mEditFeedbackEmail).skip(1);
    Observable.combineLatest(etFeedbackInputObservable, etFeedbackEmailObservable, new Func2<CharSequence, CharSequence, Boolean>() {
        @Override
        public Boolean call(CharSequence charSequence, CharSequence charSequence2) {
            boolean inputValid = !TextUtils.isEmpty(charSequence);
            boolean emailValid = !TextUtils.isEmpty(charSequence2);
            return inputValid && emailValid;
        }
    }).subscribe(new Observer<Boolean>() {
        @Override
        public void onCompleted() {
            Logger.d("onCompleted");
        }

        @Override
        public void onError(Throwable e) {
            Logger.e("onError-->" + e.toString());
        }

        @Override
        public void onNext(Boolean aBoolean) {
            //讓提交表單可以單擊
            mButtonSendFeedback.setEnabled(aBoolean);
        }
    });

在實(shí)際的項(xiàng)目開發(fā)中, combineLatest操作除了可以做一些簡單的表單校驗(yàn), 還可以做更加復(fù)雜的業(yè)務(wù)場(chǎng)景, 最重要的是遇到了這種場(chǎng)景能夠用RxJava操作符來解決.

再上家公司有這樣一個(gè)業(yè)務(wù)場(chǎng)景: 一個(gè)用戶查看自己的訂單列表(該用戶是藝術(shù)家在平臺(tái)上賣藝術(shù)品的), 界面除了展示訂單的基本信息, 還需要在Item的底部展示是哪個(gè)用戶購買的(展示購買者的頭像和名字), 但是后臺(tái)返回的JSON數(shù)據(jù)對(duì)應(yīng)的Bean如下所示 :

public class JsonOrderPage<Order> {
    public List<Order> data;
    public Paging paging;
}

似乎感覺也沒什么, 但是后臺(tái)返回的Order對(duì)象里對(duì)于購買者的信息只有購買者的id, 但是界面上需要顯示購買者的名字和頭像. 說白了需要根據(jù)購買者的id來獲取購買者的信息. 如果后端返回的僅僅是個(gè)List就好了, 那就用flatMap操作符很好的解決了. 當(dāng)然最直觀的解決方式就是for循序環(huán), 如下所示:

Observable<JsonOrderPage> observableUser = xxx;
observableJsonOrderPage.flatMap(new Func1<JsonOrderPage, Observable<JsonOrderPage>>() {
    @Override
    public Observable<JsonOrderPage> call(JsonOrderPage page) {
        List<Order> orders = page.getData();
        for (Order order : orders) {
            //同步請(qǐng)求獲取購買者的信息
            User buyer = userApi.getUserInfoById(order.getBuyer().getBuyerId());
            //把獲取的購買者信息賦值給Order
            order.setBuyer(buyer);
        }
    }
})

雖然實(shí)現(xiàn)了功能, 但是總覺得不爽, 都用了RxJava這么牛逼的框架, 還要用for循環(huán)操作. 有沒有比較優(yōu)雅的方式來實(shí)現(xiàn)這種需求呢?

**這種需求就是 對(duì)A對(duì)象上的某個(gè)List屬性進(jìn)行RxJava操作, 然后把操作的結(jié)果再重新賦給原來的A對(duì)象. **

我們知道對(duì)A對(duì)象的List進(jìn)行操作, RxJava操作后返回的就是List, 無法獲取原來的A對(duì)象, 除非我們先獲取A對(duì)象, 然后通過變量保存下, 當(dāng)處理完List后,把最終的List賦值給A對(duì)象, 這種方法還不如第一種呢? 我想的是有沒有一種途徑全程用RxJava操作符來做.

這種需求還是很多的, 比如返回一個(gè)用戶對(duì)象(User), 里面有個(gè)List屬性表示他的好友, 但是關(guān)于好友的信息只有id. 界面展示的他的好友信息.

類似這樣的需求, 需要對(duì)數(shù)據(jù)的某個(gè)子數(shù)據(jù)進(jìn)行單獨(dú)處理, 可以使用combineLatest來優(yōu)雅的實(shí)現(xiàn) :

userApi = ApiServiceFactory.createService(UserApi.class);
//獲取用戶信息
userApi.fetchUserInfo(null)
        .flatMap(new Func1<User, Observable<User>>() {
            @Override
            public Observable<User> call(User user) {
                printLog(tvLogs, "----fetch a user---- \n", getUserString(user));
                
                return fetchFriendsInfo(user);
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<User>() {
            @Override
            public void call(User user) {
                printLog(tvLogs, "----process his friends by id---- \n", getUserString(user));
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        });



//這個(gè)方法才是實(shí)現(xiàn)的核心
private Observable<User> fetchFriendsInfo(User user) {
    
    //保存User的數(shù)據(jù)
    Observable<User> observableUser = Observable.just(user);
    
    //對(duì)User的好友列表進(jìn)行單獨(dú)處理
    Observable<List<User>> observableUsers = Observable.from(user.getFriends())
            .flatMap(new Func1<User, Observable<User>>() {
                @Override
                public Observable<User> call(User user) {
                    //根據(jù)好友ID獲取更完整的信息
                    return userApi.fetchUserInfo(user.getId() + "");
                }
            })
            .toList();

    //對(duì)用戶User信息和他的好友信息進(jìn)行合并.
    return Observable.combineLatest(observableUser, observableUsers, new Func2<User, List<User>, User>() {
        @Override
        public User call(User user, List<User> users) {
            user.setFriends(users);
            return user;
        }
    });
}

上面的代碼還是很簡單的, 注釋也比較詳細(xì). 大致的意思就是把User信息分為兩個(gè)部分:

一部分是User的基本信(Observable<User>), 一部分是User好友列表(Observable<List<User>>) 然后把兩個(gè)最終數(shù)據(jù)進(jìn)行組合就是我們最終需要的數(shù)據(jù)了.

我在github上已經(jīng)寫了相關(guān)例子, 運(yùn)行效果如下所示:

這里寫圖片描述

本文的例子放在github上https://github.com/chiclaim/android-sample/tree/master/rxjava

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蔬螟,一起剝皮案震驚了整個(gè)濱河市此迅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旧巾,老刑警劉巖耸序,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鲁猩,居然都是意外死亡坎怪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門廓握,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搅窿,“玉大人,你說我怎么就攤上這事隙券∧杏Γ” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵娱仔,是天一觀的道長沐飘。 經(jīng)常有香客問我,道長牲迫,這世上最難降的妖魔是什么耐朴? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮盹憎,結(jié)果婚禮上筛峭,老公的妹妹穿的比我還像新娘。我一直安慰自己陪每,他們只是感情好影晓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奶稠,像睡著了一般俯艰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锌订,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天竹握,我揣著相機(jī)與錄音,去河邊找鬼辆飘。 笑死啦辐,一個(gè)胖子當(dāng)著我的面吹牛谓传,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芹关,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼续挟,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了侥衬?” 一聲冷哼從身側(cè)響起诗祸,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轴总,沒想到半個(gè)月后直颅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怀樟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年功偿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片往堡。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡械荷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虑灰,到底是詐尸還是另有隱情吨瞎,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布瘩缆,位于F島的核電站关拒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏庸娱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一谐算、第九天 我趴在偏房一處隱蔽的房頂上張望熟尉。 院中可真熱鬧,春花似錦洲脂、人聲如沸斤儿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽往果。三九已至,卻和暖如春一铅,著一層夾襖步出監(jiān)牢的瞬間陕贮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工潘飘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肮之,地道東北人掉缺。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像戈擒,于是被迫代替她去往敵國和親眶明。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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

  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位筐高,與響應(yīng)式編程作為結(jié)合使用的搜囱,對(duì)什么是操作、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,855評(píng)論 0 10
  • 注:只包含標(biāo)準(zhǔn)包中的操作符柑土,用于個(gè)人學(xué)習(xí)及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 2,193評(píng)論 2 8
  • 作者: maplejaw本篇只解析標(biāo)準(zhǔn)包中的操作符犬辰。對(duì)于擴(kuò)展包,由于使用率較低冰单,如有需求幌缝,請(qǐng)讀者自行查閱文檔。 創(chuàng)...
    maplejaw_閱讀 45,658評(píng)論 8 93
  • 創(chuàng)建操作 用于創(chuàng)建Observable的操作符Create通過調(diào)用觀察者的方法從頭創(chuàng)建一個(gè)ObservableEm...
    rkua閱讀 1,826評(píng)論 0 1
  • 前言 按照官方的分類诫欠,操作符大致分為以下幾種: Creating Observables(Observable的創(chuàng)...
    小玉1991閱讀 1,050評(píng)論 0 1