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操作符实现获取验证码功能
十五、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上已经写了相关例子, 运行效果如下所示:

这里写图片描述


本文的例子放在github上 https://github.com/chiclaim/AndroidAll

猜你喜欢

转载自blog.csdn.net/johnny901114/article/details/61191723