观察者模式中除了用过EventBus外,Rxjava也是必需掌握的一个框架,本文主要介绍Rxjava的主要功能以及使用方式。
概念
在RxJava中,函数响应式编程具体表现为一个观察者(Observer)订阅一个可观察对象(Observable),通过创建可观察对象发射数据流,经过一系列操作符(Operators)加工处理和线程调度器(Scheduler)在不同线程间的转发,最后由观察者接受并做出响应的一个过程。
Rxjava的使用
1.引入依赖包:
implementation "io.reactivex.rxjava2:rxjava:2.1.12"
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
2.创建被观察者:
//被观察者
Observable novel=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<int> emitter) throws Exception {
emitter.onNext(1);
emitter.onComplete();
}
});
3.创建观察者
//观察者
Observer<String> reader=new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
mDisposable=d;
Log.e(TAG,"onSubscribe");
}
@Override
public void onNext(int value) {
Log.e(TAG,"onNext:"+value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"onError="+e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG,"onComplete()");
}
};
4.建立订阅关系
novel.subscribe(reader);
5.链式调用:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<int> emitter) throws Exception {
emitter.onNext(1);
emitter.onComplete();
}
})
.observeOn(AndroidSchedulers.mainThread())//回调在主线程
.subscribeOn(Schedulers.io())//执行在io线程
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG,"onSubscribe");
}
@Override
public void onNext(int value) {
Log.e(TAG,"onNext:"+value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"onError="+e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG,"onComplete()");
}
});
基本的使用就是上面这些了,在链式调用的过程中,我们看到在异步的过程中使用了Schedulers,即调度器。
异步
Rxjava的核心就是异步操作,能够在操作IO或者网络传输时使用线程池,在接收返回数据时在主线程显示。
这里就涉及了一个名词叫Scheduler,调度器,调度器总共有五种调度方式:
- Schedulers.single(): 拥有一个线程单例,所有的任务都在这一个线程中执行,当线程中有任务时,其它任务会按照先进先出的的顺序执行。
- Schedulers.newThread(): 每执行一个任务创建一个新线程,不具有线程缓存机制 Scheduler.io(): 用于读写SD卡文件,查询数据库,访问网络,具有线程缓存机制,调度器接收到任务后,先检查线程池中是否有空闲的线程,如果有,则复用,没有则创建新的线程,效率比newThread 高。
- Schedulers.computation(): 用于CPU密集型计算任务,即不会被I/O等操作限制性能的耗时操作,比如xml.json文件解析,Bitmap图片压缩取样等,具有固定的线程池。
- Schedulers.trampoline(): 在当前线程的任务立即执行,如果当前线程有任务在执行,则会将其暂停,等插进来的任务执行完之后再接着执行。
- AndroidSchedulers,.mainThread(): 在Android UI线程中执行任务,为Android开发定制。
subscribeOn来指定对数据的处理运行在特定的线程调度器Scheduler上,直到遇到observeOn改变线程调度器若多次设定,则只有一次起作用。observeOn指定下游操作运行在特定的线程调度器Scheduler上。若多次设定,每次均起作用。
Observer在接收到数据后,延迟了两秒才处理,但是Observable依然在Observer将数据处理完之后才开始发射下一条。Schedulers.trampoline()的作用在当前线程立即执行任务,如果当前线程有任务在执行,则会将其暂停,等插入进来的任务执行完之后,再将未完成的任务接着执行。
通过Schedulers.single()将数据的发射,处理,接收在Schedulers.single()的线程单例中排队执行,当此线程中有任务执行时,其他任务将会按照先进先出的顺序依次执行 。
Rxjava 操作符
操作符分以下几类:
创建:
1 : create
2 : just :创建一个Observable,可接受一个或者多个参数
3: fromArray:创建一个Observable,接受一个数据,并将数组逐一发送
4: fromIterable:创建一个Observable,接受一个可迭代对象,并将可迭代对象的数据逐一发送
5: range:创建一个Observable, 发送一个范围内的整数数据,如Observable.range(1,10)
过滤:
filter:filter使用Predicate函数接口传入条件值,来判断每一个传入的参数是否满足条件,如果满足,则继续向下传递,不满足则过滤调。
distinct: 过滤调重复的数据项
链式调用,可以先用distinct过滤调重复的数据,然后再用filter筛选合适的数据
变换:
map: 对Observable发射的每一项数据应用一个函数,执行变换操作
map操作符,需要接收一个函数接口Function<T,R>的实例化对象,实现接口内R apply(T t)的方法,在此方法中可以对接收到的数据t进行变换后返回。
flapmap:将一个发射数据的Observable变换为多个Observable,然后将多个Observable发射的数据合并到一个Observable中进行发射
首先,用just操作符,发射三个数组,通过flatMap变换,将每个数组中的元素用操作符fromArray取出后逐一发射
组合:
mergeWith:合并多个Observable发射的数据,可能会让Observable发射的数据交错。
concatWith: 同mergeWith一样,用以合并多个Observable发射的数据,但是concatWith不会让Observable发射的数据交错。
聚合:
zipWith:将多个Obversable发射的数据,通过一个函数BiFunction对对应位置的数据处理后放到一个新的Observable中发射,所发射的数据个数与最少的Observabel中的一样多。
背压策略
观察者除了observer还可以是consumer;被观察者除了observable还可以是Flowable,背压支持。那就产生了一个新的概念,背压(backpressure)什么是背压呢?按照理解是上游发射数据的速度远远大于下游,而且下游接收是一个新的线程,从而下游不会阻断上游的发送,造成上游不断新增线程,造成内存溢出。
Rxjava2相对于Rxjava1最大的更新就是把对背压问题的处理逻辑从Observable抽取出来产生了新的可观察对象Flowable。
那么Flowable可以取代Observable吗?不能,虽然Observable能解决的问题Flowable也能解决,但由于Flowable对数据加工处理的各种操作符都添加了背压支持,所以运行效率要比Observable慢得多。
Flowable和Observable的异同之处:
发射器中均有onNext,OnError,onComplete方法;
不同:1 create方法中多了一个BackpressureStrategy
2 订阅器Subscriber中,方法onSubscribe回调的参数不是Disposable而是Subscription
3 Flowable发射数据时,使用特有的发射器FlowableEmitter,而不同于Observable的ObservableEmitter.
BackpressureStrateqy中缓存池的上限为128,超过上限就会报这五个异常:
MISSING --->MissingEmitter 当超过128时,后面的
ERROR ---> ErrorAsyncEmitter 当超过128时,MissingBackpressureException异常。
DROP ---> DropAsyncEmitter 如果Flowable的异步缓存池满了,会丢掉上游发送的数据,等缓存池中数据清理之后才重新接收。
LATEST ---> LatestAsyncEmitter 不管缓存池的状态如何,LATEST都会将最后一条数据强行放入缓存池中
BUFFER ---> BufferAsyncEmitter 如果Flowable默认的异步缓存池满了,会通过此缓存池暂存数据,它与Observable的异步缓存池一样,可以无限制向里添加数据,不会抛出MissingBackpressureException异常,但会导致OOM。
通过代理对原始发射器进行了包装
如何解决背压问题?
上游e.requested能获取当前可用的线程池,只需要在数量为0时,不发射数据,当数量重新恢复时再发射;下游默认s.request(1) 默认请求数为1。
五类观察者和订阅者
ObservableSource/Observer
可通过onNext方法发送单条数据或者数据序列,通过onComplete发送完成通知或通过onError发送异常通知,不支持背压策略。
Publisher/Subscriber
在ObservableSource/Observer基础上进行了改进,可通过背压策略处理背压问题,但效率没有第一组高。
以下三组是新的响应式关系的实现,在Rxjava1中没有,可看做是ObservableSource/Observer的简化版
SingleSource/SingleObserver
不能发送数据序列或完成通知,只能通过onSuccess方法发送单条数据,或者通过onError发送异常通知
CompletableSource/CompletableObserve
不能发送任何形式的数据(单条数据或数据序列),只能通过onComplete发送完成通知或者通过onError发送异常通知
MaybeSource/MaybeObserver
可通过onSuccess发送单条数据,通过onComplete发送完成通知或者通过onError发送一条异常通知