RxJava最重要的概念是什么?

12 篇文章 0 订阅
6 篇文章 0 订阅

RxJava最重要的概念是什么?几个操作符方便你把数据变来变去,方便你做线程调度,让你不用去看callback hell?确实很方便,但如果只看到这一层,未免过于肤浅。以我用RxJava这几年肤浅的体验来看,RxJava最大的作用是提供一个优秀的,现成的响应式/流式调用封装,而你只需付出些许学习成本就可以少做很多工作。一个RxJava的调用链从create开始到subscribe结束,可以大概把整个调用链分为上游、中游、下游,上游数据源,中游数据变换,下游数据接收&展示。除非你变更整条调用链的数据结构,变更其中一块对外输出的数据,否则你修改上中下游任何一块都不会影响到其它地方,整条调用链可以起于应用的网络层,终于UI层,完美契合中大规模工程中的分层架构。举个例子,我的应用中用户的系统账号和IM账号是分开的,IM是第三方SDK,而且用户并不是一定要登录IM才能使用应用,但是进入IM相关的模块时,需要检查用户是否登录,如果登录,检查IM是否登录,如果没登录,检查是否缓存IM账号,通过接口获取IM账号并登录IM。这么一段逻辑用RxJava怎么做?//reloadAccount = true : 无论当前状态如何都重新加载账号数据并执行登录

public Observable<Object> checkAndLogin(boolean reloadAccount) {
    // 数据上游,检查账号状态决定下一步操作
    return Observable.create((emitter) -> {
        if (!reloadAccount && isIMLogin) {
            emitter.onNext(ACTION_ALREADY_LOGIN);
            return;
        }
        if (!reloadAccount && hasCacheData()) {
            emitter.onNext(ACTION_CACHE_LOGIN);
            return;
        }
        // 用户没有登录系统账号,向下游返回异常
        if (!UserDataManager.isLogin()) {
            emitter.onError(new ApiExecption("请先登录"));
            return;
        }
        emitter.onNext(ACTION_RELOAD_LOGIN);
    })
    // 数据变换,是否需要请求账号数据
    .flatMap((Function)(actionCode) -> {
        if(actionCode == ACTION_RELOAD_LOGIN) {
            return NetworkManager.getIMAccount();
        }
        //按下游定义数据格式构建缓存数据发送
        JSONObject cacheData = new JSONObject();
        cacheData.put("isLogin", actionCode == ACTION_ALREADY_LOGIN);
        cacheData.put("userId", cachedUserId);
        cacheData.put("password", cachedUserPwd);
        return Observable.just(cacheData);
    })
    // 执行IM登录
    .flatMap((Function) (data) -> {
        if ( data.optBoolean("isLogin", false)) {
            return Observable.just(new Object());
        }
        String userId = data.getString("userId");
        String password = data.getString("password");
        if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(password)) {
            return Observable.error(new ApiExecption("获取IM账号失败"));
        }
        cacheAccountData(userId, password);
        // 返回RxJava封装过后的第三方IM登录方法
        return rxIMLogin();
    })
    // 出现登录异常时请求账号数据重试
    .onErrorResumeNext((Function)(throwable) -> {
        // 如果没有重试次数则直接将异常交给下游
        if (retryTimes <= 0) {
            return Observable.error(throwable);
        }
        retryTimes--;
        return checkAndLogin(true);
    })
    // 登录成功重试次数重置
    .map((Function)(o) -> {
        retryTimes = 1;
        return o;
    })
    .subscribeOn(Schedulers.io())
    .observableOn(AndroidSchedulers.mainThread());
}

这么一段“中游”代码,封装了是否强制重新加载账号、检查IM是否登录、检查系统账号是否登录、请求IM账号、缓存已获取账号、执行IM登录,出错重连,异常处理。而下游的subscribe订阅,只需关心“IM登录了没?”,在初始化界面,如果登录了就去请求预加载数据,如果没登录就pass,不管异常。在IM界面,如果登录了就去请求其它IM数据,没登录直接弹Alert提示异常并退出界面。这个例子应该能比较好的说明“流式调用”是怎么回事了吧。你用其它手段能实现这一套逻辑吗?当然能,而且很简单,不过是你用另外一种方式实现了“流式调用”而已,只是可能没有RxJava实现的代码这么紧密,修改方便罢了。分层架构就是这样,面向协议编程。比如分页加载,我不管你上游中游要做多少事,下游UI层只关心拿到List,是否有更多,触发加载更多时调用;中游只关心把数据变换成下游所需的数据,RxJava用这些数据操作符实现了中游不用关心上游数据,上游用接口请求数据下来,还是Observable.just()一段假数据下来,对中游、下游没有丝毫影响。这种调用形式在某些客户端先用假数据看效果,后端接口以后给到的情景下,实现和替换成本极其低廉。说了这么多总结一下,组件间调用可以看作一个应用的“神经系统”,而RxJava相当于一套优秀的,现成的“神经信号传递机制”,要用,就要替换整个应用“神经系统的信号传递机制”。如果你的应用现行的机制已经运行良好使用方便,且替换成本高昂,那么完全没有必要为了Rx而集成RxJava,或者说你在写随时可能拿去其它环境使用的组件,那更不能随便集成SDK;但如果你应用现在的相互调用写的乱七八糟,或者开始搭建新应用,为什么放着现成的机制不拿过来用而要自己再写一套蹩脚的callback呢?

RxJava2和Rxjava1的区别:https://www.jianshu.com/p/4ac34c1411ca
RxJava1到Rxjava2踩过的坑:https://www.jianshu.com/p/6d644ca1678f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鼾声鼾语

感谢您的支持鼓励!

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

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

打赏作者

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

抵扣说明:

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

余额充值