RxJava(十二)combineLatest操作符的高级使用

RxJava系列文章目录导读:

一、RxJava create操作符的用法和源码分析
二、RxJava map操作符用法详解
三、RxJava flatMap操作符用法详解
四、RxJava concatMap操作符用法详解
五、RxJava onErrorResumeNext操作符实现app与服务器间token机制
六、RxJava retryWhen操作符实现错误重试机制
七、RxJava 使用debounce操作符优化app搜索功能
八、RxJava concat操作处理多数据源
九、RxJava zip操作符在Android中的实际使用场景
十、RxJava switchIfEmpty操作符实现Android检查本地缓存逻辑判断
十一、RxJava defer操作符实现代码支持链式调用
十二、combineLatest操作符的高级使用
十三、RxJava导致Fragment Activity内存泄漏问题
十四、interval、takeWhile操作符实现获取验证码功能


combineLatest 操作符用来将多个Observable发射的数据组装起来然后在发射. 通过Func类来组装多个Observable发射的数据, 等到最后一个Observable发射数据了, 然后把所有发射的数据交给Fun进行组合, 然后把组合后的数据发射出去.

看到网上绝大部分都是用 combineLatest 来做Android表单的校验, 总感觉有点大材小用. 如只有表单都只有值了了, 提交按钮才可用:

    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);
        }
    });

在实际的项目开发中, combineLatest操作除了可以做一些简单的表单校验, 还可以做更加复杂的业务场景, 最重要的是遇到了这种场景能够用RxJava操作符来解决.

再上家公司有这样一个业务场景: 一个用户查看自己的订单列表(该用户是艺术家在平台上卖艺术品的), 界面除了展示订单的基本信息, 还需要在Item的底部展示是哪个用户购买的(展示购买者的头像和名字), 但是后台返回的JSON数据对应的Bean如下所示 :

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

似乎感觉也没什么, 但是后台返回的Order对象里对于购买者的信息只有购买者的id, 但是界面上需要显示购买者的名字和头像. 说白了需要根据购买者的id来获取购买者的信息. 如果后端返回的仅仅是个List就好了, 那就用flatMap操作符很好的解决了. 当然最直观的解决方式就是for循序环, 如下所示:

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) {
            //同步请求获取购买者的信息
            User buyer = userApi.getUserInfoById(order.getBuyer().getBuyerId());
            //把获取的购买者信息赋值给Order
            order.setBuyer(buyer);
        }
    }
})

虽然实现了功能, 但是总觉得不爽, 都用了RxJava这么牛逼的框架, 还要用for循环操作. 有没有比较优雅的方式来实现这种需求呢?

**这种需求就是 对A对象上的某个List属性进行RxJava操作, 然后把操作的结果再重新赋给原来的A对象. **

我们知道对A对象的List进行操作, RxJava操作后返回的就是List, 无法获取原来的A对象, 除非我们先获取A对象, 然后通过变量保存下, 当处理完List后,把最终的List赋值给A对象, 这种方法还不如第一种呢? 我想的是有没有一种途径全程用RxJava操作符来做.

这种需求还是很多的, 比如返回一个用户对象(User), 里面有个List属性表示他的好友, 但是关于好友的信息只有id. 界面展示的他的好友信息.

类似这样的需求, 需要对数据的某个子数据进行单独处理, 可以使用combineLatest来优雅的实现 :

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();
            }
        });



//这个方法才是实现的核心
private Observable<User> fetchFriendsInfo(User user) {
    
    //保存User的数据
    Observable<User> observableUser = Observable.just(user);
    
    //对User的好友列表进行单独处理
    Observable<List<User>> observableUsers = Observable.from(user.getFriends())
            .flatMap(new Func1<User, Observable<User>>() {
                @Override
                public Observable<User> call(User user) {
                    //根据好友ID获取更完整的信息
                    return userApi.fetchUserInfo(user.getId() + "");
                }
            })
            .toList();

    //对用户User信息和他的好友信息进行合并.
    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;
        }
    });
}

上面的代码还是很简单的, 注释也比较详细. 大致的意思就是把User信息分为两个部分:

一部分是User的基本信(Observable<User>), 一部分是User好友列表(Observable<List<User>>) 然后把两个最终数据进行组合就是我们最终需要的数据了.

我在github上已经写了相关例子, 运行效果如下所示:

这里写图片描述

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容