前言:
对于Rxjava大家并不陌生,它是基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大Android 开发者的欢迎。
对于RxJava中,观察者和被观察者具有两种订阅模式,及同步订阅,异步订阅;
同步订阅:即在同一线程中,被观察者每发一件事件,必须等到观察者接受处理后,才能发送下一个事件
异步订阅:观察者和被观察者不在同一个线程中,即产生了被观察者发送事件的速度与观察者接受事件的速度不一致,大多数情况是被观察者发送事件的速度大于观察者接受事件的速度,这个就是产生背压的原因.
RxJava2.0在RxJava1.0的基础上,采用背压策略来解决:因被观察者发送事件速度 与 观察者接收事件速度不匹配(一般是前者 快于 后者),从而导致观察者无法及时响应 / 处理所有 被观察者发送事件 的问题.
正文:
在RxJava2中真正实现背压策略的类是: Flowable,它是Observable的一种新实现.Flowable简单的使用如下:
//Flowable创建被观察者 Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(@NonNull FlowableEmitter<Integer> emitter) throws Exception { emitter.onNext(1); emitter.onComplete(); } }, BackpressureStrategy.ERROR)//需要传入的被压参数 .subscribeOn(Schedulers.io())//设置悲观者在子线程中 .observeOn(AndroidSchedulers.mainThread())//设置观察者在主线程中 //进行订阅 .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { //制定观察者接受事件的个数(响应式拉取),默认是最大 s.request(Long.MAX_VALUE); } @Override public void onNext(Integer integer) { Log.d("TAG","接受数据:" + integer); } @Override public void onError(Throwable t) { } @Override public void onComplete() { } });
接下来通过背压策略的原理及Flowable的使用,来说明RxJava2如何通过Flowable来解决背压问题
1.控制观察者接受事件的速度-------------------------------响应式拉取
即当观察者设置s.request()方法之后,即设置了观察者接受事件的个数
// 创建被观察者Flowable Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { // 一共发送4个事件 Log.d("TAG", "发送事件 1"); emitter.onNext(1); Log.d("TAG", "发送事件 2"); emitter.onNext(2); Log.d("TAG", "发送事件 3"); emitter.onNext(3); Log.d("TAG", "发送事件 4"); emitter.onNext(4); Log.d("TAG", "发送完成"); emitter.onComplete(); } }, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io()) // 设置被观察者在io线程中进行 .observeOn(AndroidSchedulers.mainThread()) // 设置观察者在主线程中进行 .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { // 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription // 相同点:Subscription参数具备Disposable参数的作用,即Disposable.dispose()切断连接, 同样的调用Subscription.cancel()切断连接 // 不同点:Subscription增加了void request(long n) s.request(3);//设置观察者只接受3个事件 // 作用:决定观察者能够接收多少个事件 // 如设置了s.request(3),这就说明观察者能够接收3个事件(多出的事件存放在缓存区) // 官方默认推荐使用Long.MAX_VALUE,即s.request(Long.MAX_VALUE); } @Override public void onNext(Integer integer) { Log.d("TAG", "接收到了事件" + integer); } @Override public void onError(Throwable t) { Log.w("TAG", "onError: ", t); } @Override public void onComplete() { Log.d("TAG", "onComplete"); } });
那么,问题来了,当观察者不设置s.request()方法,会出现什么呢?
当观察者不设置接受事件的个数时,被观察者依然会发送事件,只不过该事件会存入缓存区(大小128,这个大小可以查看Flowable源码)当如果发送的事件个数大于缓存区大小,即就会抛出异常.
// 创建被观察者Flowable Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { for (int i = 0 ; i < 129; i ++){ emitter.onNext(i); } emitter.onComplete(); } }, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io()) // 设置被观察者在io线程中进行 .observeOn(AndroidSchedulers.mainThread()) // 设置观察者在主线程中进行 .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { // 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription // 相同点:Subscription参数具备Disposable参数的作用,即Disposable.dispose()切断连接, 同样的调用Subscription.cancel()切断连接 // 不同点:Subscription增加了void request(long n) // s.request(3);//设置观察者只接受3个事件 // 作用:决定观察者能够接收多少个事件 // 如设置了s.request(3),这就说明观察者能够接收3个事件(多出的事件存放在缓存区) // 官方默认推荐使用Long.MAX_VALUE,即s.request(Long.MAX_VALUE); } @Override public void onNext(Integer integer) { Log.d("TAG", "接收到了事件" + integer); } @Override public void onError(Throwable t) { Log.w("TAG", "onError: ", t); } @Override public void onComplete() { Log.d("TAG", "onComplete"); } });
2.控制被观察者发送事件的速度----------------------------反馈控制
1>在同步订阅中,因为观察者和被观察者处于同一线程中,即被观察者可以得知观察者接受事件的个数,如下所示为FlowableEmitter部分源码,其中requested()方法即可获取观察者接受事件的个数
public interface FlowableEmitter<T> extends Emitter<T> { void setDisposable(@Nullable Disposable s); void setCancellable(@Nullable Cancellable c); /** * The current outstanding request amount. * <p>This method is thread-safe. * @return the current outstanding request amount */ long requested(); boolean isCancelled(); @NonNull FlowableEmitter<T> serialize(); }
代码实现如下:
// 创建被观察者Flowable Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { long requested = emitter.requested(); Log.d("TAG","被观察者可以得知观察者接收事件的个数为:" + requested); for(int i = 0; i < requested; i ++ ){ emitter.onNext(i); } emitter.onComplete(); } }, BackpressureStrategy.ERROR) .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { // 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription // 相同点:Subscription参数具备Disposable参数的作用,即Disposable.dispose()切断连接, 同样的调用Subscription.cancel()切断连接 // 不同点:Subscription增加了void request(long n) s.request(3);//设置观察者只接受3个事件 // 作用:决定观察者能够接收多少个事件 // 如设置了s.request(3),这就说明观察者能够接收3个事件(多出的事件存放在缓存区) // 官方默认推荐使用Long.MAX_VALUE,即s.request(Long.MAX_VALUE); } @Override public void onNext(Integer integer) { Log.d("TAG", "接收到了事件" + integer); } @Override public void onError(Throwable t) { Log.w("TAG", "onError: ", t); } @Override public void onComplete() { Log.d("TAG", "onComplete"); } });2> 异步订阅,因为观察者和被观察者不在同一个线程中,所以被观察者无法获取观察者接受事件的个数,那么是如何解决的,这个问题及 采用背压策略模式:BackpressureStrategy稍后更新