学习笔记(四)Rxjava3详解和在Android中的使用:基本概念
添加依赖:
implementation 'io.reactivex.rxjava3:rxjava:3.0.13'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
添加java8的编译
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
1)、基本概念
RxJava是响应式编程(Reactive Extensions)的java实现,它基于观察者模式的实现了异步编程接口。
基础字段说明:
Iterable : 迭代器,用于遍历
Observable: 被观察对象(异动源头),数据改变时通知观察者。
Observer : 观察者(观察异动)。
emit : 发射,发布,发出,有异动时的动作。
items : 条目,指单一发射的数据项。
流对象 : 在RxJava的文档中,emission, emits, item, event, signal, data and message都被认为在数据流中被传递的数据对象。
背压(Backpressure) : 当上下游在不同的线程中,通过Observable发射,处理,响应数据流时,如果上游发射数据的速度快于下游接收处理数据的速度,这样对于那些没来得及处理的数据就会造成积压,这些数据既不会丢失,也不会被垃圾回收机制回收,而是存放在一个异步缓存池中,如果缓存池中的数据一直得不到处理,越积越多,最后就会造成内存溢出,这便是响应式编程中的背压(backpressure)问题。
为此,RxJava带来了backpressure的概念。背压是一种流量的控制步骤,在不知道上流还有多少数据的情形下控制内存的使用,表示它们还能处理多少数据。背压是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略
在Rxjava1.0中,有的Observable支持背压,有的不支持,为了解决这种问题,2.0把支持背压和不支持背压的Observable区分开来:支持背压的有Flowable类,不支持背压的有Observable,Single, Maybe and Completable类。
1、在订阅的时候如果使用FlowableSubscriber,那么需要通过s.request(Long.MAX_VALUE)去主动请求上游的数据项。如果遇到背压报错的时候,FlowableSubscriber默认已经将错误try-catch,并通过onError()进行回调,程序并不会崩溃;
2、在订阅的时候如果使用Consumer(事件消费者),那么不需要主动去请求上游数据,默认已经调用了s.request(Long.MAX_VALUE)。如果遇到背压报错、且对Throwable的Consumer没有new出来,则程序直接崩溃;
3、背压策略的上游的默认缓存池是128。
背压策略类型 :
error, 缓冲区大概在128
buffer, 缓冲区在1000左右
drop, 把存不下的事件丢弃
latest, 只保留最新的
missing, 缺省设置,不做任何操作
事件调度器 : RxJava事件发出去并不是置之不顾,要有合理的管理者来管理它们,在合适的时机再进行释放,这样才不会导致内存泄漏,这里的管理者我们称为事件调度器(或事件管理者)CompositeDisposable。
2)、线程调度器(Schedulers)
Android中比较方便的线程切换。
调度器 功能
AndroidSchedulers.mainThread() 需要引用rxandroid, 切换到UI线程
Schedulers.computation() 用于计算任务,如事件循环和回调处理,默认线程数等于处理器数量
Schedulers.io() 用于IO密集型任务,如异步阻塞IO操作,这个调度器的线程池会根据需求调整,它默认是一个CacheThreadScheduler
Schedulers.newThread() 为每一个任务创建一个新线程
Schedulers.trampoline() 在当前线程中插入目标任务并立刻执行,如当前线程中有任务在执行则将其暂停,等插入的目标任务执行完毕后,再继续前面暂停的任务。
Scheduler.from(executor) 指定Executor作为调度器
3)、基类
RxJava 3 中的基类相比RxJava 2 没啥改变,主要有以下几个基类:
io.reactivex.Flowable 发送0个N个的数据,支持Reactive-Streams和背压
io.reactivex.Observable 发送0个N个的数据,不支持背压,
io.reactivex.Single 只能发送单个数据或者一个错误
io.reactivex.Completable 没有发送任何数据,但只处理 onComplete 和 onError 事件。
io.reactivex.Maybe 能够发射0或者1个数据,要么成功,要么失败。
4)、Observables的"热"和"冷"
Observable什么时候开始发射数据序列?这取决于Observable的实现,一个"热"的Observable可能一创建完就开始发射数据,因此所有后续订阅它的观察者可能从序列中间的某个位置开始接受数据(有一些数据错过了)。一个"冷"的Observable会一直等待,直到有观察者订阅它才开始发射数据,因此这个观察者可以确保会收到整个数据序列。
在一些ReactiveX实现里,还存在一种被称作Connectable的Observable,不管有没有观察者订阅它,这种Observable都不会开始发射数据,除非Connect方法被调用。
5)、Rxjava的简单使用
需要知道的是,RxJava以观察者模式为骨架,有两种常见的观察者模式:
Observable(被观察者)/Observer(观察者)
Flowable(被观察者)/Subscriber(观察者)
见下图:
RxJava2/3中,Observeable用于订阅Observer,是不支持背压的,而Flowable用于订阅Subscriber,是支持背压(Backpressure)的。
(1)、Observable/Observer
最基础的用法:
//被观察者(Observable抽象类,ObservableOnSubscribe接口)
val observable = Observable.create(object : ObservableOnSubscribe<Int> {
override fun subscribe(emitter: ObservableEmitter<Int>) {
emitter.onNext(1)
emitter.onNext(2)
emitter.onComplete()
}
});
//观察者(Observer接口)
val observer = object : Observer<Int> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(o: Int) {
Log.d("", "收到的数据:${o}")
}
override fun onError(e: Throwable) {
}
override fun onComplete() {
}
}
//关联
observable.subscribe(observer)
这种观察者模型不支持背压:当被观察者快速发送大量数据时,下游不会做其他处理,即使数据大量堆积,调用链也不会报MissingBackpressureException,消耗内存过大只会OOM。所以,当我们使用Observable/Observer的时候,我们需要考虑的是,数据量是不是很大(官方给出以1000个事件为分界线作为参考)
(2)、Flowable/Subscriber
最基础的用法:
//Flowable
var sub: Subscription? = null
Flowable.range(0, 3).subscribe(object : Subscriber<Int> {
override fun onSubscribe(s: Subscription) {
sub = s
sub?.request(1) //请求一条数据
//s?.cancel() 这里cancel后事件就不下发了
}
override fun onNext(t: Int?) {
if (t == 1) {
sub?.cancel() //事件中途被取消,不回调onComplete; 被cancel后再request无效,因为数据源已被清除
} else {
sub?.request(1)
}
Log.d("Flowable", "onNext:${t}")
}
override fun onError(t: Throwable?) {
Log.d("Flowable", "onError:${t}")
}
override fun onComplete() {
Log.d("Flowable", "onComplete")
}
})
Flowable是支持背压的,也就是说,一般而言,上游的被观察者会响应下游观察者的数据请求,下游调用request(n)来告诉上游发送多少个数据。这样避免了大量数据堆积在调用链上,使内存一直处于较低水平。
当然,Flowable也可以通过creat()来创建:
//Flowable
Flowable.create(object : FlowableOnSubscribe<Int> {
override fun subscribe(emitter: FlowableEmitter<Int>) {
emitter.onNext(1)
emitter.onComplete()
}
}, BackpressureStrategy.BUFFER) //需要指定背压策略
.subscribe(object : Subscriber<Int> {
override fun onSubscribe(s: Subscription?) {
}
override fun onNext(t: Int?) {
}
override fun onError(t: Throwable?) {
}
override fun onComplete() {
}
})
Flowable虽然可以通过create()来创建,但是你必须指定背压的策略,以保证你创建的Flowable是支持背压的。
根据上面的代码的结果输出中可以看到,当我们调用subscription.request(n)方法的时候,不等onSubscribe()中后面的代码执行,就会立刻执行到onNext方法,因此,如果你在onNext方法中使用到需要初始化的类时,应当尽量在subscription.request(n)这个方法调用之前做好初始化的工作;
当然,这也不是绝对的,我在测试的时候发现,通过create()自定义Flowable的时候,即使调用了subscription.request(n)方法,也会等onSubscribe()方法中后面的代码都执行完之后,才开始调用onNext。
(3)、Single/SingleObserver
Single类似于Observable,不同的是,它总是只发射一个值,或者一个错误通知,而不是发射一系列的值(当然就不存在背压问题),所以当你使用一个单一连续事件流,这样你可以使用Single。Single观察者只包含两个事件,一个是正常处理成功的onSuccess,另一个是处理失败的onError。因此,不同于Observable需要三个方法onNext, onError, onCompleted,订阅Single只需要两个方法:
onSuccess - Single发射单个的值到这个方法
onError - 如果无法发射需要的值,Single发射一个Throwable对象到这个方法
Single只会调用这两个方法中的一个,而且只会调用一次,调用了任何一个方法之后,订阅关系终止。
Single的操作符
操作符 返回值 说明
compose Single 创建一个自定义的操作符
concat and concatWith Observable 连接多个Single和Observable发射的数据
create Single 调用观察者的create方法创建一个Single
error Single 返回一个立即给订阅者发射错误通知的Single
flatMap Single 返回一个Single,它发射对原Single的数据执行flatMap操作后的结果
flatMapObservable Observable 返回一个Observable,它发射对原Single的数据执行flatMap操作后的结果
from Single 将Future转换成Single
just Single 返回一个发射一个指定值的Single
map Single 返回一个Single,它发射对原Single的数据执行map操作后的结果
merge Single 将一个Single(它发射的数据是另一个Single,假设为B)转换成另一个Single(它发射来自另一个Single(B)的数据)
merge and mergeWith Observable 合并发射来自多个Single的数据
observeOn Single 指示Single在指定的调度程序上调用订阅者的方法
onErrorReturn Single 将一个发射错误通知的Single转换成一个发射指定数据项的Single
subscribeOn Single 指示Single在指定的调度程序上执行操作
timeout Single 它给原有的Single添加超时控制,如果超时了就发射一个错误通知
toSingle Single 将一个发射单个值的Observable转换为一个Single
zip and zipWith Single 将多个Single转换为一个,后者发射的数据是对前者应用一个函数后的结果
简单使用:
Single.create(object : SingleOnSubscribe<String> {
override fun subscribe(emitter: SingleEmitter<String>) {
//发送数据(下面二个方法只会回调前面那个,后面的事件不处理)
emitter.onError(NumberFormatException())
emitter.onSuccess("onSuccess")
}
}).subscribe(object : SingleObserver<String> {
override fun onSubscribe(d: Disposable?) {
Log.d("SingleObserver","onSubscribe")
}
override fun onSuccess(t: String?) {
Log.d("SingleObserver","onSuccess:${t}")
}
override fun onError(e: Throwable?) {
Log.d("SingleObserver","onError:${e.toString()}")
}
})
(4)、Completable/CompletableObserver
如果你的观察者连onNext事件都不关心,可以使用Completable,它只有onComplete和onError两个事件:
Completable.create(object : CompletableOnSubscribe {
override fun subscribe(emitter: CompletableEmitter) { //被观察者
emitter.onComplete()
}
}).subscribe(object : CompletableObserver { //观察者
override fun onSubscribe(d: Disposable?) {
}
override fun onComplete() {
Log.d("Completable", "onComplete")
}
override fun onError(e: Throwable?) {
}
})
要转换成其他类型的被观察者,也是可以使用toFlowable()、toObservable()等方法去转换。
(5)、Maybe/MaybeObserver
如果你有一个需求是可能发送一个数据或者不会发送任何数据,这时候你就需要Maybe,它类似于Single和Completable的混合体。
Maybe可能会调用以下其中一种情况(也就是所谓的Maybe):
onSuccess或者onError
onComplete或者onError
可以看到onSuccess和onComplete是互斥的存在,例子代码如下:
Maybe.create(object : MaybeOnSubscribe<String> {
override fun subscribe(emitter: MaybeEmitter<String>) { //被观察者
//下面二个事件互斥,只会调用第一个
emitter.onSuccess("测试")
emitter.onComplete()
}
}).subscribe(object : MaybeObserver<String> { //观察者
override fun onSubscribe(d: Disposable) {
Log.d("Maybe", "onSubscribe")
}
override fun onSuccess(s: String) {
Log.d("Maybe", "onSuccess:${s}")
}
override fun onComplete() {
Log.d("Maybe", "onComplete")
}
override fun onError(e: Throwable?) {
Log.d("Maybe", "onError")
}
})
要转换成其他类型的被观察者,也是可以使用toFlowable()、toObservable()等方法去转换。
实际使用示例:
Maybe.just(isLogin()) //判断是否登录
.subscribe(object : MaybeObserver<Boolean> { //观察者
override fun onSubscribe(d: Disposable) {
Log.d("Maybe", "onSubscribe")
}
override fun onSuccess(b: Boolean) {
if (b) {
Log.d("Maybe", "onSuccess:已经登录")
} else {
Log.d("Maybe", "onSuccess:没有登录")
}
}
override fun onComplete() {
Log.d("Maybe", "onComplete")
}
override fun onError(e: Throwable?) {
Log.d("Maybe", "onError")
}
})
上面就是Maybe/MaybeObserver的普通用法,你可以看到,实际上,这种观察者模式并不用于发送大量数据,而是发送单个数据,也就是说,当你只想要某个事件的结果(true or false)的时候,你可以用这种观察者模式。
(6)、事件调度器释放事件
基础代码:
//创建事件调度器
val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val subscribe = Observable.create(object : ObservableOnSubscribe<String> {
override fun subscribe(emitter: ObservableEmitter<String>?) {
}
}).subscribe( //订阅多种事件
object : Consumer<String> {
override fun accept(t: String) {
//对应onNext()
}
}, object : Consumer<Throwable> {
override fun accept(throwable: Throwable) {
//对应onError()
}
}, object : Action {
override fun run() {
//对应onComplete()
}
})
//事件调度器的使用
mCompositeDisposable.add(subscribe);
mCompositeDisposable.clear();
}
CompositeDisposable提供的方法中,都是对事件的管理
dispose():释放所有事件
clear():释放所有事件,实现同dispose()
add():增加某个事件
addAll():增加所有事件
remove():移除某个事件并释放
delete():移除某个事件
Rxjava中,被观察者不能接收null作为数据源。