我学 rxjava 2(1)- 简单上手

本系列目录:我学 rxjava - 目录
Android 知识梳理目录:知识梳理

啥叫 rxjava

官方文档解释:

RxJava:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
// 翻译:RxJava 是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库

通俗解释:

//  Android中的 AsyncTask 、Handler

rxjava 完成的工作就是异步,期中采用了响应式编程的理念,现在响应式编程不明白没关系,不影响你用 rxjava 完成开发,响应式编程现在桃李满天下呢,用不了多久就明白了并深有体会了,推荐学完 rxjava 再去看 Google 的 AAC 响应式组件,你就对响应式编程非常明白了,这里不要脸的推荐自己的文章:Android Architecture Components 开发架构

添加依赖

dependencies {

// Android 支持 Rxjava
// 此处一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'

// 衔接 Retrofit & RxJava
// 此处一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

}

依赖可能的错误如下:


944365-b3574a3808108707.png

请在相关 module 中的 build.gradle 中

android {
    ...
    packagingOptions {
        exclude 'META-INF/rxjava.properties'
    }
}

rxjava 采用的是观察者设计模式, 必然就是在 Observable 被观察者 身上注册 Observer 观察者了,我们定义 Observable 如何产生,产生什么数据,然后 Observer 如何消费数据,整个套路基本就是这样,当然里面有很设置和变化啦

rxjava 里面有很多没接触过的,不好记的关键字,记住这些关键字才能玩的转 rxjava

关键字:

  • 被观察者(Observable) 产生事件 顾客
  • 观察者(Observer) 接收事件,并给出响应动作 厨房
  • 订阅(Subscribe) 连接 被观察者 & 观察者 服务员
  • 事件(Event) 被观察者 & 观察者 沟通的载体 菜式

创建 Observable 被观察者对象

rxjava 中的 Observable 被观察者一般都是要传入数据,或是能产生数据的对象才能创建出来的,所以我也喜欢管 Observable 叫数据源,要是没有 Observable 这个数据源提供数据,后面怎么消费数据呢

  // 传入可以产生数据的对象方式创建 Observable  对象
  Observable<String> object = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                // emitter 是用来提供数据的,我们也叫发射 
                emitter.onNext("数据");
            }
        });
    
        // 直接用数据创建 Observable  对象,数据可以是单个也可以是动态数组,集合
        Observable<String> just = Observable.just("aaa");
        Observable<String> list = Observable.just("", "", "");

创建 Observer 观察者并定义处理事件的行为

 Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                // 观察者在接受到数据之前,先执行该方法
            }

            @Override
            public void onNext(String value) {
                // 观察者此时接受到数据,可以处理数据了
            }

            @Override
            public void onError(Throwable e) {
                // 观察者接受到错误信号,进行相关处理
            }

            @Override
            public void onComplete() {
                //  观察者此时已经处理完数据了,执行该方法最最后的收尾工作。
            }
        };

Observer 观察者里面有4个方法,上面的方法里的文字基本描述清楚了,然后我想说下 Error 错误信号可以用前面 数据源里面的 emitter.onError(xxx) 自己发射出来,也会接受到这个过程中系统抛出的异常。onComplete 是不管什么情况最后都会走的。

现在 Observable 有了 ,Observer 也有了,他俩一注册就成了。

observable.subscribe(observer);

我们要注意数据产生的点,Observable 只是提供数据,不是我们创建一个 Observable 对象就去获取数据,发射数据了,而是再 Observer 注册到 Observable 身上那一瞬间,Observable 才还是提供数据,是远程数据的开始从远程获取数据,是现成数据的开始发射数据给 Observer 消费数据。

线程变换

观察者设计模式只是对 数据源 和 数据消费者 的一种组织形式,还不是 rxjava 最核心的内容,大家可以不要忘了 rxjava 可是替代 asynctask ,handle 这样的异步线程啊,方便的多线程操作和切换才是 rxjava 最大的核心内容

rxjava 提供一下几个线程池:

  • Schedulers.immediate()
    当前线程
  • AndroidSchedulers.mainThread()
    Android主线程
  • Schedulers.newThread()
    常规新线程
  • Schedulers.io()
    io操作线程,可以进行网络请求、读写文件等io密集型操作
  • Schedulers.computation()
    CPU计算操作线程,线程数据同 CPU 核心数

相关的线程控制 API 如下,这里是简单的写的

 observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
  • subscribeOn 是描述 observable 中产生数据的方法执行在哪个线程
  • observeOn 是描述 observer 消费数据的方法执行在哪个线程
  • 这里 数据源是从网络获取数据,UI 线程消费数据

关于 Observer 的变形

我们按照上面的 方式创建一个 Observer 来,需要实现4个方法才行,丰富多看着乱,页影响 rxjava 的链式调用阅读效果,官方提供了如下的 Observer 创建方法

   // 表示观察者不对被观察者发送的事件作出任何响应(但被观察者还是可以继续发送事件)
    public final Disposable subscribe()
 
    // 表示观察者只对被观察者发送的Next事件作出响应
    public final Disposable subscribe(Consumer<? super T> onNext) {}
  
    // 表示观察者只对被观察者发送的Next事件 & Error事件作出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
    
    // 表示观察者只对被观察者发送的Next事件、Error事件 & Complete事件作出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
    
    // 表示观察者只对被观察者发送的Next事件、Error事件 、Complete事件 & onSubscribe事件作出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
  
    // 表示观察者对被观察者发送的任何事件都作出响应
    public final void subscribe(Observer<? super T> observer) {}

Consumer 是一个方法包装接口,Observer 中的4个方法对应 4个 Consumer 方法包装接口,subscribe 注册方法中可以接受 1 - 4个 Consumer 可变参数,根据下面图 4个方法的顺序,传入一个是代替 onNext 方法,传入2个是代替 onNext、onError 方法

Consumer_方法包装接口_替换方法顺序如下

关于可能的内存泄露的处理

这些注册的 Observer 我们都是在 activity 中进行的,按照:匿名内部类持有外不累的引用,这个注册的匿名 Observer 对象其实是把我们的 activity 带出 activity 的生命周期外去了,Observable 持有这些注册的 Observer 对象引用,那么间接的也持有了 activity 的引用,在 activity 关闭时这就是个麻烦事了,原因不就是老生常谈的内存泄露了嘛...

针对这个情况,其实我们是游处理办法的,那就是 Disposable 管道这个对象,Disposable 是实际管理 Observable和 Observer 关系的操作类,我们用 Disposable 就可以接触 Observable 和 Observer 的注册的关系。

Disposable 有2种获取方式,一个是注册时我们使用 Consumer 代替 Observer ,然后我们就可以获取这个 Disposable 对象,调用 disposable.dispose() 就可以解绑

        Disposable disposable = Observable
                .just("22")
                .subscribe(
                        new Consumer<String>() {
                            @Override
                            public void accept(String s) throws Exception {

                            }
                        }
                        , new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Exception {

                            }
                        });

        disposable.dispose();

或者是 Observer 对象中的 onSubscribe(Disposable d) 方法中,我们可以获取到 Disposable 对象

若是我们有多个 disposable 对象,我们可以使用官方提供管理类

        CompositeDisposable compositeDisposable = new CompositeDisposable();
        // 添加 disposable 管道对象用于统一管理
        compositeDisposable.add( disposable );
        // 统一解绑
        compositeDisposable.dispose();

一个完成的流程示例

rxjava 2 中添加了不少 doOnXXX 方法,打都是在指定的 OnXXX 方法之前执行的。

需要注意的是 2个 observeOn 方法中间夹一个 doOnNext 方法,这是说前一个 observeOn 指定 这个 doOnNext 方法的执行线程,后一个 observeOn 方法执行最终执行 Observer 执行线程,其实这个就是 rxjava 的变换操作符的基础

  Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                Log.d(TAG, " subscribe.../thread: " + Thread.currentThread().getName() + "处理数据,产生事件");
                e.onNext("HH");
            }
        })
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        Log.d(TAG, " doOnSubscribe.../thread: " + Thread.currentThread().getName() + "预热方法(doOnSubscribe函数),最先执行");
                    }
                })
                .observeOn(Schedulers.computation())
                .doOnNext(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.d(TAG, " doOnNext.../thread: " + Thread.currentThread().getName() + "数据处理后,先执行我,再发射数据");
                    }
                })
                .observeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d(TAG, " onSubscribe.../thread: " + Thread.currentThread().getName() + "预热方法(观察者),最先执行");
                    }

                    @Override
                    public void onNext(@NonNull String s) {
                        Log.d(TAG, " onNext.../thread: " + Thread.currentThread().getName() + "接受数据,消费事件");
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

一个完整的简单实用就是这样了,这里各种生命周期函数写的比较全了,直接看结果:


Snip20171010_25.png

按照执行顺序:

  • doOnSubscribe() 方法最先执行,所在线程是UI 线程,调用测试方法的线程
  • subscribe / onSubscribe() ,之后是观察者新添加方法,所在线程也是UI 线程,和doOnSubscribe()一样,这俩用一个就行
  • create / subscribe() ,接下来是处理数据,发射事件的线程
  • doOnNext(),这个是在数据发射之前执行的,我们可以指定一个线程,这里指定的计算线程,要是不注定,则使用发射事件的线程
  • Observer / onNext(),最后就是我们接受事件啦。

注意上面各种方法所在线程,不要弄混了

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

推荐阅读更多精彩内容