关于RxJava

0 处识

没有高大上的理由,就是厌烦了AsyncTaskHandler
感觉代码臃肿、开发效率低、内存泄露,但是当年就是这样过来的,后来看到RxJava优雅的切换线程,震惊了!为了这么优雅的方式就要深入研究他一下(当时不知道有那么多操作符,而且也不知道处理复杂的业务逻辑也可以那么优雅)

  • 线程切换
    当年就是被
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

这两句给吸引的,subscribeOn和observeOn来切换线程。
subscribeOn:影响被观察者的执行线程,当使用多个 subscribeOn() 的时候,只有第一个 subscribeOn() 起作用
observeOn:影响观察者的执行线程,如果想要多次改变线程,可以多次使用 observeOn
现在整理了一下代码

private static <T> Observable.Transformer<T, T> createIOToMainThreadScheduler() {
        return tObservable -> tObservable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

不用每次都麻烦的调用这两行。

  1. Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程
  2. Schedulers.newThread(): 总是启用新线程,并在新线程执行操作
  3. Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler
  4. Schedulers.computation(): CPU 密集型计算所使用的 Scheduler
  5. AndroidSchedulers.mainThread(): 在 Android 主线程运行
  • 内存泄露
    虽然很方便使用了RxJava的线程切换发现还是会内存泄露,不过可以用一下三种方法解决
  1. CompositeSubscription
    可以把页面中的请求都添加到CompositeSubscription中,然后在onDestory的时候,统一取消
  2. Rxlifecycle
    第三方库取消订阅,把请求和组件的生命周期绑定到了一起,这样组件生命周期结束请求也结束了
  3. 自己动手
@Override
    public void onDestroyView() {
        super.onDestroyView();
        unsubscribe();
    }

    protected void unsubscribe() {
        if (subscription != null && !subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }
    }

比如项目中突然有个逻辑用到了Rxjava,没有生命周期也不方便建立一个CompositeSubscription就自己动手。

  • 操作符
    再到后来慢慢熟悉,发现有很多丰富的操作符可以使用,并且都是可以解决很多负责的现实问题的,比如create、from、filter等简单的,下面说一下项目中用到比较多的
  1. interval:创建一个按照给定的时间间隔发射从0开始的整数序列的Observable<Long>
    在注册、手机号登陆的时候,倒计时会用到
  2. concat:接收若干个Observables,发射有序数据流
    在取数据缓存的时候用到,内存缓存、本地缓存、网络,哪一层有数据立即返回
Observable.concat(memorySource, diskSource, networkSource)
                        .takeFirst(new Func1<String, Boolean>() {
                            @Override
                            public Boolean call(String s) {
                                return s != null;
                            }
                        })
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<String>() {
                            @Override
                            public void call(String s) {
                            }
                        }, new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                
                            }
                        });
  1. zip: 使用一个函数组合多个Observable发射的数据集合,然后再发射这个结果
    这个用的多,因为一般页面初始时都不止一个网络请求,我们希望多个网络请求结束后在一次性展示页面,所以这个可以很好的解决这个问题
  2. flatMap: 上面zip操作符是多个没有关系的Observable的组合,flatMap是可以把多个有先后顺序的Observable组合在一起的,比如先注册,注册成功了去登录,登录成功了调用用户信息 这个需求就可以用flatMap把他们组合在一起
  3. zipWith:
/**
     * 重试机制
     * 重复次数:5
     * 间隔时间:interval的次方数,比如interval=2,第一次2s, 第二次4s, 第三次8s, 第四次16s, 第五次32s 结束
     * 条件:没网络不重试,自定义逻辑不重试,网络连接并且网络不稳定才重试
     */
    public static class RetryWhenProcess implements Func1<Observable<? extends Throwable>, Observable<?>> {

        private long mInterval;

        public RetryWhenProcess(long interval) {
            mInterval = interval;
        }

        @Override
        public Observable<?> call(Observable<? extends Throwable> observable) {
            return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                @Override
                public Observable<?> call(Throwable throwable) {
                    return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                        @Override
                        public Observable<?> call(Throwable throwable) {
                            //没有网络,直接返回,不重试了
                            if (throwable instanceof UnknownHostException || !NetWorkUtils.isNetworkAvailable()) {
                                return Observable.error(throwable);
                            }
                            return Observable.just(throwable).zipWith(Observable.range(1, 5), new Func2<Throwable, Integer, Integer>() {
                                @Override
                                public Integer call(Throwable throwable, Integer i) {
                                    return i;
                                }
                            }).flatMap(new Func1<Integer, Observable<? extends Long>>() {
                                @Override
                                public Observable<? extends Long> call(Integer retryCount) {

                                    return Observable.timer((long) Math.pow(mInterval, retryCount), TimeUnit.SECONDS);
                                }
                            });
                        }
                    });
                }
            });
        }
    }

  1. sample: 定期扫描源Observable产生的结果,在指定的间隔周期内进行采样
    当时在项目中解决了背压问题,上游发送的流过快,下游就会throw error,用sample采样来减慢上游发送流的速度
  2. throttleFirst: 功能防抖,一个btn连续快速点击多次,如果不作处理,会连续调用click事件
  3. debuounce:联想搜索功能,在一定的时间不发送变化,在执行搜索动作
  4. ...
    操作符太多了,而且还没有用一遍,后来工作中发现可悲的是遇到一个复杂的业务逻辑不知道有没有操作符能解决这个问题,所以就推荐一个地址Rxjava操作符

总结

用了很长一段时间了,发现好久没有用Handler、AsyncTask了,为什么呢?RxJava简洁、提升了开发效率、响应式编程、代码优雅等优点,需要研究一下源码看看底层代码是如何的,结果代码太庞大了,不过可以带着疑问去一段一段的读,不能像读Retrofit一样一口气读完,比如整个流是从哪里开始的(subscribe()开始的)?怎么切换的线程(handler)?底层是什么样的线程(比如Schedulers.io()是一个无数量上限的线程池,可以重用空闲的线程)?等问题
Rxjava已经升级到2.x,请看Demo

MVP和RxJava

现在一般使用RxJava+Retrofit+OkHttp组合做为应用框架的根基,但是为什么是他们呢?他们是如何组合在一起的?为什么和MVP是好基友?

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

推荐阅读更多精彩内容

  • 本篇文章介主要绍RxJava中操作符是以函数作为基本单位,与响应式编程作为结合使用的,对什么是操作、操作符都有哪些...
    嘎啦果安卓兽阅读 2,853评论 0 10
  • 作者寄语 很久之前就想写一个专题,专写Android开发框架,专题的名字叫 XXX 从入门到放弃 ,沉淀了这么久,...
    戴定康阅读 7,620评论 13 85
  • 我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy阅读 5,464评论 7 62
  • 最近项目里面有用到Rxjava框架,感觉很强大的巨作,所以在网上搜了很多相关文章,发现一片文章很不错,今天把这篇文...
    Scus阅读 6,871评论 2 50
  • 小路上一个人走着 风是我的伴侣 发梢飘动 是它在嬉戏 它调皮 影子的韵动毫无生气 模仿的也不过是自己
    白勺花开阅读 129评论 0 0