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

15 篇文章 41 订阅

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 操作符实现获取验证码功能
十五、RxJava 线程的自由切换

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 上已经写了相关例子, 运行效果如下所示:

在这里插入图片描述


如果你觉得本文帮助到你,给我个关注和赞呗!

另外,我为 Android 程序员编写了一份:超详细的 Android 程序员所需要的技术栈思维导图

如果有需要可以移步我的 GitHub -> AndroidAll,里面包含了最全的目录和对应知识点链接,帮你扫除 Android 知识点盲区。 由于篇幅原因只展示了 Android 思维导图:
超详细的Android技术栈

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiclaim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值