RxJava2
前提:
android常用基础异步工具:AsycTask,规范使用时需要继承重写作为abstract类
handler,绑定-sendMessgae-handleMessage
当需求任务数量增加,代码逐渐变混乱和繁杂
Rxjava,能简洁的实现异步操作,响应式编程,代码可读性强
认识
观察者模式
主要理解因素:observable(被观察者)、subscribe(订阅)、observer(观察者)
经典例子概念理解:处理点击按钮
点击,触发按钮产生onClick事件,响应时需要onClickListener来实现点击效果。事件发生对象(按钮)和监听处理事件对象(onClickListener)之间,通过setOnclickListener建立两者监听关系
同理,通过订阅建立被观察者和观察者之间的响应关系
基础使用
创建被观察者
常用创建操作符:
Observable.just("t","e","s","t") //just() : item最多接收10个参数
Observable.fromArray(new String[]{"test","hello"}) //fromArray(Iterable)
//直接数据就是要传递的事件本身
Observable.create(new ObservableOnSubscribe<Object>() {
@Override
public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
//产生事件
}
})
创建操作符操作后,返回Observable实例
创建观察者
观察者 : Observer 和 Consumer
public interface Observer<T> {
/**
* @since 2.0
* 给予当前订阅事件实例给观察者使用,用于取消订阅
*/
void onSubscribe(@NonNull Disposable d);
/**
* @param t
* the item emitted by the Observable
* 传递item,0或者多次被调用,onError或OnComplete后不再调用
*/
void onNext(@NonNull T t);
/**
* @param e
* the exception encountered by the Observable
*/
void onError(@NonNull Throwable e);
/**
* The {@link Observable} will not call this method if it calls {@link #onError}.
*/
void onComplete();
}
public interface Consumer<T> {
/**
* Consume the given value.
* @param t the value
* @throws Exception on error
*/
void accept(T t) throws Exception;
}
订阅 Subscribe
Observable.subscribe(Observer) //建立关系
Observable<String> observable = Observable.fromArray("t", "e", "s", "t");
//Consumer使用
observable.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.i(TAG, "Consumer.accept :" + s);
}
});
//Observer使用
observable.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "onSubscribe");
}
@Override
public void onNext(String s) {
Log.i(TAG, s);
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError");
}
@Override
public void onComplete() {
Log.i(TAG, "onComplete");
}
});
效果log:
Consumer.accept :t
Consumer.accept :e
Consumer.accept : s
Consumer.accept :t
onSubscribe
t
e
s
t
onComplete
源码部分
//当前基础使用情况下,使用Observable作为被观察者
//而观察者有Observer(onNext、onError、OnSubscibe、onComplete) vs Consumer(accept)
//从源码查看使用的区别:
public final Disposable subscribe(Consumer<? super T> onNext) {
return subscribe(onNext, Functions.ON_ERROR_MISSING, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
// 结合来看,订阅事件的观察者实际需要Observer4个方法处理实现的,而使用consumer可以让我们只需关注处理传递得到的数据,系统会创建空方法实例去补充
//订阅方法接收的其他参数方法:
public final Disposable subscribe(Consumer<? super T> onNext
, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
//可见observer的部分方法可用consumer实现,非强制性实现所有接口
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,Action onComplete, Consumer<? super Disposable> onSubscribe) {
ObjectHelper.requireNonNull(onNext, "onNext is null");
ObjectHelper.requireNonNull(onError, "onError is null");
ObjectHelper.requireNonNull(onComplete, "onComplete is null");
ObjectHelper.requireNonNull(onSubscribe, "onSubscribe is null");
//内部将consumer整合成Observer
LambdaObserver<T> ls = new LambdaObserver<T>(onNext, onError, onComplete, onSubscribe);
subscribe(ls);*
return ls;
}
consumer和observer的区别
由此部分代码得出:
Observer是完整观察者接口。
consumer内部只有一个接口,可以实现observer的某一方法(除onComplete使用Action)
可查看LambdaObserver将consumer组合成Observer使用
Disposable subscribe(consumer)
void subscribe(observer)
订阅事件的流程
//观察者订阅的主要位置
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");//判空
try {
observer = RxJavaPlugins.onSubscribe(this, observer);//hook,返回本身或处理后
ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
subscribeActual(observer);*
} catch (NullPointerException e) {
throw e;
} catch (Throwable e) {
...
}
}
查看当前observable具体的subscribeActual实现:
ObservableCreate<T>内部代码:
@Override
protected void subscribeActual(Observer<? super T> observer) {
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//使用observer创建emitter,emitter间接替代观察者被被观察者调用传递,更安全
observer.onSubscribe(parent);//传递前的准备
try {
source.subscribe(parent);//执行被观察者唯一的方法,被观察者开始行动
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
*******由此方法看出,被观察者在订阅方法执行时才开始传递事件*********
从demo看,在subscribe()调用emitter的传递方法,而Emitter接口与Observer相似拥有onNext、onError、onComplete;实际在内部封装observer的具体方法
CreateEmitter内部代码:
@Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
if (!isDisposed()) {
observer.onNext(t);
}
}
@Override
public void onError(Throwable t) {
if (!tryOnError(t)) {
RxJavaPlugins.onError(t);
}
}
//由代码可见,在真正调用observer处理前,会先判断订阅是否正常
emitter用于替换观察者,用作被Observable调用
线程调度器 Scheduler
RxJava的出现,目的在于对异步操作用了更简洁的方式。而scheduler就是用于给此订阅事件调度切换线程的。
项目中,常等待耗时请求结果显示ui的需求。
subscribeOn(scheduler) : 指定被观察者产生事件操作所处线程
observeOn(scheduler) : 指定观察者处理事件操作所处线程
RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景:
- **Schedulers.immediate() **: 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
- Schedulers.newThread() : 总是启用新线程,并在新线程执行操作。
- _Schedulers.io() _: I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
- Schedulers.computation() : 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
- 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
项目常用被观察者处于io scheduler进行耗时操作,观察者在mainThread将耗时操作的结果进行ui展示
更多使用
操作符
Observable是链式调用的,可通过调用操作符对被观察者事件进行直接操作
操作符操作后,返回处理后的Observable继续往下传递
此处以map操作符展开分析:
demo解析
Log:
receive integer is 0
receive integer is 1
receive integer is 2
receive integer is 0
Observable传递的String类型元素通过map操作符转换规则处理变更为Integer。
转换逻辑由Function.apply实现,处理完成返回Observable对象继续往下传递。
源码
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
...判空
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}// 返回 ObservableMap
由此可知,Observable操作后返回仍为Observable
那么操作符处理后的Observable有什么不同之处呢?
- ObservableMap 没有直接继承Observable。而是继承抽象类**AbstractObservableWithUpstream_ which extends Observable**_ .抽象类实现保存构建函数传入的Observable实例
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U>
implements HasUpstreamObservableSource<T> {
protected final ObservableSource<T> source;//可观察的资源
AbstractObservableWithUpstream(ObservableSource<T> source) {
this.source = source;
}
@Override
public final ObservableSource<T> source() {
return source;
}
}
- ObservableMap继承**AbstractObservableWithUpstream**,才具体实现Observable.subscibeActual()。而subscibeActual()不做传递事件工作,而是将当前Observer和操作符规则Function封装成new Observer并前一个Observable。
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new MapObserver<T, U>(t, function));
}
因此理解:通过非创建操作符创建的Observable作为Special Observable。被订阅时,不实现事件产生传递,作为中间商将操作符转换规则和当前Observer封装成new Observer 订阅处理前一个Observable。
流程理解
此流程为抽象概念理解,具体请查阅源码
- 首先:先从上往下看,树店存在而木店存在,木店存在而纸店存在。这是被订阅者的创建前提
- 过程理解:
树店相当于传递事件的Observable
木店、纸店相当于经过操作符操作后的Special Observable
ps : 这条街上,木店的创建是由于树店的存在而创建的,纸店同理。
进货商都为Observer,订货购买操作理解为订阅。
理解真正的客人,只是最初买纸的进货商,货物到他手上才是真正使用的。
此处使用方法教程理解为,店铺对于购买者给与的使用方法,理解为Function。(开店时已有合作协议,以已拿到使用方法为前提)
- 进货商A对纸店订货购买纸,产生了订阅事件,激发纸店派工人带着制纸方法进货。
- 纸店工人作为买木的进货商,向木店订货购买。激发木店派工人带着制木方法到树店进货。
- 木店工人作为买树进货商向树店订货购买,等货制木。
- 树店收到订货,将店内的树搬出来,把树传给木店工人。
- 木店工人收到树,按照制木方法,将树制造成木,传递给纸店工人。
- 纸店工人收到木后,按照制纸方法,将木造成树,传递给进货商A。
- 完成交易。
查看各类操作符,subscribeActual实现逻辑与当前解析map流程理解相同。因此以是否继承AbstractObservableWithUpstream作为判断Special Observable的要素
背压 BackPressure
来源
以subscribe()方法为分界,前面的操作作为被观察者发生事件的源头称为上游。后续的操作作于处理事件称为下游。
发生前提:上游和下游是异步操作,上游传递事件速度>下游处理事件速度,那么事件就会存放缓存池中。那么当缓存池中存放的事件越存越多,超过bufferSize(默认128),就会出现内存溢出。这就是背压问题。
Observable没有作背压问题处理,所以出现Flowable。
Flowable作为被观察者,通过设置背压策略来避免背压问题。
Flowable传递的数据流,以及对数据加工处理的各操作符都添加了背压支持,附加了额外的逻辑,其运行效率要比 Observable 低得多,应酌情考虑条件谨慎使用。
Flowable
基本用法与Observable相似,增加了背压策略指定:
1.在create创建操作符中:指定
public static <T> Flowable<T> create(FlowableOnSubscribe<T> source, BackpressureStrategy mode) {
ObjectHelper.requireNonNull(source, "source is null");
ObjectHelper.requireNonNull(mode, "mode is null");
return RxJavaPlugins.onAssembly(new FlowableCreate<T>(source, mode));
}
2.或使用操作符指定:
Flowable.just("t", "e", "s", "t")
.onBackpressureBuffer()
.subscribe();
BackpressureStrategy 背压策略
public enum BackpressureStrategy {
MISSING,
ERROR,
BUFFER,
DROP,
LATEST
}
- MISSING:传递的事件不缓存,不丢掉。直接传递到下游,若出现背压问题,直接抛出异常。
- ERROR:当缓存池中的数据超限,不能再插入缓存,则会抛出
MissingBackpressureException
异常 - BUFFER:默认策略。没有限制缓池大小,不限制插入事件数据。不会抛出异常,但会导致OOM。
- DROP:若异步缓存池满了,会直接丢掉将要放入缓存池中的数据。
- LATEST:与DROP相似,不同的是,不管缓存池的状态如何,LATEST都会将最后一条数据强行放入缓存池中。
具体实现源码可在FlowableCreate查看策略不同而创建的Emitter处理
Subscriber
注意,当被观察者使用Flowable时,观察者需要使用Subsciber配合使用。与Observer使用方法类似,不同在于
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(10);//说明下游有效接收上游事件传递总量
}
Subscription.request()必须调用,否则下游不响应上游的事件传递。同时若上游传递超过num的设定,下游也不再响应。
Disposable
使用Disposable实例表示整个订阅事件。
disposable 出现在:
Disposable disposable = Obervable.subscibe(Consumer)
...
.subscribe(new Observer<Object>{
public void onSubscribe(Dispoable d){
disposable = d
}
})
内部实现两个接口 :
void dispose() : 调用以取消当前订阅事件,释放资源。
boolean isDisposed() : 判断当前订阅事件是否已取消,常用于在订阅流程中作安全判断,未取消才继续执行。
项目中,常用CompositeDisposable 管理订阅事件。
管理
有订阅事件发生,CompositeDisposable 将其加入管理
CompositeDisposable.add(dispoable)
当关闭当前调用RxJava开启订阅事件的容器时,可能会存在订阅事件未完成或订阅事件未被取消释放资源,因此在容器的生命周期要进行资源释放:
@Override
public void onDestroy() {
if (mCompositeDisposable != null && mCompositeDisposable.size() > 0) {
mCompositeDisposable.clear();
}
}