本系列目录:我学 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'
}
依赖可能的错误如下:
请在相关 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 object = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
// emitter 是用来提供数据的,我们也叫发射
emitter.onNext("数据");
}
});
// 直接用数据创建 Observable 对象,数据可以是单个也可以是动态数组,集合
Observable just = Observable.just("aaa");
Observable list = Observable.just("", "", "");
创建 Observer 观察者并定义处理事件的行为
Observer observer = new Observer() {
@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 方法
关于可能的内存泄露的处理
这些注册的 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() {
@Override
public void accept(String s) throws Exception {
}
}
, new Consumer() {
@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() {
@Override
public void subscribe(@NonNull ObservableEmitter e) throws Exception {
Log.d(TAG, " subscribe.../thread: " + Thread.currentThread().getName() + "处理数据,产生事件");
e.onNext("HH");
}
})
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer() {
@Override
public void accept(Disposable disposable) throws Exception {
Log.d(TAG, " doOnSubscribe.../thread: " + Thread.currentThread().getName() + "预热方法(doOnSubscribe函数),最先执行");
}
})
.observeOn(Schedulers.computation())
.doOnNext(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, " doOnNext.../thread: " + Thread.currentThread().getName() + "数据处理后,先执行我,再发射数据");
}
})
.observeOn(Schedulers.newThread())
.subscribe(new Observer() {
@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() {
}
});
一个完整的简单实用就是这样了,这里各种生命周期函数写的比较全了,直接看结果:
按照执行顺序:
- doOnSubscribe() 方法最先执行,所在线程是UI 线程,调用测试方法的线程
- subscribe / onSubscribe() ,之后是观察者新添加方法,所在线程也是UI 线程,和doOnSubscribe()一样,这俩用一个就行
- create / subscribe() ,接下来是处理数据,发射事件的线程
- doOnNext(),这个是在数据发射之前执行的,我们可以指定一个线程,这里指定的计算线程,要是不注定,则使用发射事件的线程
- Observer / onNext(),最后就是我们接受事件啦。
注意上面各种方法所在线程,不要弄混了