本章节讲述RxJava的背压问题。
一.背景
<1> 前言
RxJava是一种扩展的观察者模式。观察者和被观察者发生订阅后。可以时刻观察被观察者。被观察者发生变化时,观察者会收到相关的消息。
RxJava中观察者和被观察者发生订阅,可以同步也可以异步。
异步订阅时,如果被观察者短时间内连续发送多条onNext消息。观察者可能来不及接收。这就会出现被观察者和观察者消息不匹配的问题。从而导致观察者无法及时响应&处理所有发送过来事件的消息。最终可能导致缓存区溢出或者事件丢失。这种问题要解决,那怎么解决呢?背压解决,那么背压策略是什么呢。
<2> 背压策略简介
控制事件流速。即控制被观察者发送事件速度和观察者接收事件的速度。
<3>背压策略作用
在异步订阅关系 中,控制事件发送和事件接收的速度。注意背压的使用观察者和被观察者一定要是异步订阅的。
<4>背压策略的具体实现
在 RxJava2.X版本中采用 Flowable(非阻塞式背压) 实现 背压策略。
<5> Flowable与Observable的区别
上面提到可以使用Flowable创建被观察者。而前几篇连载的RxJava内容讲述都是使用的Observable创建被观察者。那么两者有什么区别呢。
Observable 在 RxJava2.X版本 中新的实现叫做 Flowable。同时旧的Observable也保留了。因为在 RxJava 1.x版本中,有很多事件不被能正确的背压,从而抛出MissingBackpressureException。
比如
在RxJava1.x版本中的 observeOn,因为是切换了消费者的线程,因此内部实现用队列存储事件。在 Android 中默认的 buffersize 大小是16,因此当消费比生产慢时, 队列中的数目积累到超过16个,就会抛出MissingBackpressureException。
在RxJava2.x版本中的 Observable 不再支持背压,而Flowable支持非阻塞式的背压。Flowable是RxJava2.0中专门用于应对背压(Backpressure)问题。
所谓背压,即生产者的速度大于消费者的速度带来的问题,比如在Android中常见的点击事件,点击过快则经常会造成点击两次的效果。其中,Flowable默认队列大小为128。并且规范要求,所有的操作符强制支持背压。幸运的是, Flowable 中的操作符大多与旧有的 Observable 类似。
二.基础代码&说明
<1> Gradle配置
implementation 'io.reactivex.rxjava2:rxjava:2.0.7'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
说明
[1] RxJava&RxAndroid 版本须一致 即都是2.x版本
RxAndroid 必须依赖对应版本的RxJava。官方解释。
Because RxAndroid releases are few and far between, it is recommended you also
explicitly depend on RxJava's latest version for bug fixes and new features.
[2] 因为之前项目中使用的是2.0.1版本,所以好多与背压相关的类找不到。这里改成2.0.7版本即可。
[3] 发现一些类所处的包位置不同。
比如 Flowable类
比如 Subscriber类
<2> 基础代码
package com.example.mydemo.rxjava;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.example.mydemo.R;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class RxJavaActivity extends AppCompatActivity {
private Subscription mSubscription;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
method();
}
/**
* RxJava Flowable创建被观察者 背压
*/
public void method() {
Flowable.create(new FlowableOnSubscribe<Object>() {
@Override
public void subscribe(FlowableEmitter<Object> e) throws Exception {
if (null == e) {
return;
}
if (!e.isCancelled()) {
e.onNext("Flowable创建被观察者 被观察者发送第1波数据");
e.onNext("Flowable创建被观察者 被观察者发送第2波数据");
e.onNext("Flowable创建被观察者 被观察者发送第3波数据");
e.onComplete();
}
Log.d("TAG", "Flowable创建被观察者 被观察者 subscribe方法 线程----:" + Thread.currentThread().getName());
}
}, BackpressureStrategy.LATEST)
.subscribeOn(Schedulers.io())//被观察者在io线程中进行
.observeOn(AndroidSchedulers.mainThread())//观察者在主线程中进行
.subscribe(new Subscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
if (null == s) {
return;
}
mSubscription = s;
mSubscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(Object o) {
if (null == o) {
return;
}
Log.d("TAG", "Flowable创建被观察者 观察者 onNext方法 o.toString()----:" + o.toString());
Log.d("TAG", "Flowable创建被观察者 观察者 onNext方法 线程----:" + Thread.currentThread().getName());
}
@Override
public void onError(Throwable t) {
if (null == t) {
return;
}
Log.d("TAG", "Flowable创建被观察者 观察者 onError方法 t.toString()----:" + t.toString());
Log.d("TAG", "Flowable创建被观察者 观察者 onError方法 线程----:" + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d("TAG", "Flowable创建被观察者 观察者 onComplete方法 ");
Log.d("TAG", "Flowable创建被观察者 观察者 onComplete方法 线程----:" + Thread.currentThread().getName());
}
});
}
/**
* onDestroy方法 取消订阅
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mSubscription) {
mSubscription.cancel();
Log.d("TAG", "退出页面 取消订阅");
}
}
}
<3> 结果
D/TAG: Flowable创建被观察者 被观察者 subscribe方法 线程----:RxCachedThreadScheduler-1
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第1波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 线程----:main
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第2波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 线程----:main
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第3波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 线程----:main
D/TAG: Flowable创建被观察者 观察者 onComplete方法
D/TAG: Flowable创建被观察者 观察者 onComplete方法 线程----:main
<4> 关闭页面
D/TAG: 退出页面 取消订阅
<5> 说明
使用Flowable抽象类创建被观察者和使用Observable抽象类创建被观察者还是有一些不同的。
比如create操作符时传入了第二个参数BackpressureStrategy.LATEST。
再比如观察者的onSubscribe方法中参数是Subscription类型。会继续讲解。
三.BackpressureStrategy参数具体讲解
上述使用Flowable抽象类创建被观察者 需要传两个参数。
源码
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:枚举 BackpressureStrategy mode 具体有哪些值呢,每个值又是什么含义呢。下面讲解。
<1> BackpressureStrategy 取值&含义
public enum BackpressureStrategy {
/**
* OnNext events are written without any buffering or dropping.
* Downstream has to deal with any overflow.
* <p>Useful when one applies one of the custom-parameter onBackpressureXXX operators.
*/
MISSING,
/**
* Signals a MissingBackpressureException in case the downstream can't keep up.
*/
ERROR,
/**
* Buffers <em>all</em> onNext values until the downstream consumes it.
*/
BUFFER,
/**
* Drops the most recent onNext value if the downstream can't keep up.
*/
DROP,
/**
* Keeps only the latest onNext value, overwriting any previous value if the
* downstream can't keep up.
*/
LATEST
}
字段 | 含义 |
MISSING | 缓存区满时 友好提示 |
ERROR | 缓存区满时 直接抛异常 |
BUFFER | 缓存区满时 将缓存区设置无限大 注意内存溢出 |
DROP | 缓存区满时 事件丢失 保留[0,127]条数据 即 前 128条数据 |
LATEST | 缓存区满时 事件丢失 保留[0,127]条数据+超出的最后一条数据 |
<2> 具体代码说明
上述可知使用Flowable抽象类创建被观察者 默认缓存大小128。
[1] BackpressureStrategy.MISSING 模式
代码
package com.example.mydemo.rxjava;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.example.mydemo.R;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class RxJavaActivity extends AppCompatActivity {
private Subscription mSubscription;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxjava);
method();
}
/**
* RxJava Flowable创建被观察者 背压
*/
public void method() {
Flowable.create(new FlowableOnSubscribe<Object>() {
@Override
public void subscribe(FlowableEmitter<Object> e) throws Exception {
if (null == e) {
return;
}
if (!e.isCancelled()) {
for (int i = 0; i < 150; i++) {
e.onNext("Flowable创建被观察者 被观察者发送第 " + i + " 波数据");
}
e.onComplete();
}
}
}, BackpressureStrategy.MISSING)
.subscribeOn(Schedulers.io())//被观察者在io线程中进行
.observeOn(AndroidSchedulers.mainThread())//观察者在主线程中进行
.subscribe(new Subscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
if (null == s) {
return;
}
mSubscription = s;
mSubscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(Object o) {
if (null == o) {
return;
}
Log.d("TAG", "Flowable创建被观察者 观察者 onNext方法 o.toString()----:" + o.toString());
}
@Override
public void onError(Throwable t) {
if (null == t) {
return;
}
Log.d("TAG", "Flowable创建被观察者 观察者 onError方法 t.toString()----:" + t.toString());
}
@Override
public void onComplete() {
Log.d("TAG", "Flowable创建被观察者 观察者 onComplete方法 ");
}
});
}
/**
* onDestroy方法 取消订阅
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mSubscription) {
mSubscription.cancel();
Log.d("TAG", "退出页面 取消订阅");
}
}
}
结果
D/TAG: Flowable创建被观察者 观察者 onError方法 t.toString()----:io.reactivex.exceptions.MissingBackpressureException: Queue is full?!
说明
使用 BackpressureStrategy.MISSING 模式时 当被观察者发出超出128条数据时 走了onError方法。具体错误提示如上。
[2] BackpressureStrategy.ERROR 模式
修改上述代码 背压模式为 BackpressureStrategy.ERROR 模式 其他不变。
结果
D/TAG: Flowable创建被观察者 观察者 onError方法 t.toString()----:io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
说明
使用 BackpressureStrategy.ERROR 模式 时 当被观察者发出超出128条数据时 走了onError方法。具体错误提示如上。
[3] BackpressureStrategy.BUFFER 模式
修改上述代码 背压模式为 BackpressureStrategy.BUFFER 模式 其他不变。
结果
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 0 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 1 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 2 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 3 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 4 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 5 波数据
...
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 145 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 146 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 147 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 148 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 149 波数据
D/TAG: Flowable创建被观察者 观察者 onComplete方法
说明
使用 BackpressureStrategy.BUFFER 模式 时 当被观察者发出超出128条数据时 流程正常。全部输出包括超出的部分消息。
[4] BackpressureStrategy.DROP 模式
修改上述代码 背压模式为 BackpressureStrategy.DROP 模式 其他不变。
结果
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 0 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 1 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 2 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 3 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 4 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 5 波数据
...
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 123 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 124 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 125 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 126 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 127 波数据
D/TAG: Flowable创建被观察者 观察者 onComplete方法
说明
使用 BackpressureStrategy.DROP 模式 时 当被观察者发出超出128条数据时 流程正常。输出[0,127]条数据。
[5] BackpressureStrategy.LATEST 模式
修改上述代码 背压模式为 BackpressureStrategy.LATEST 模式 其他不变。
结果
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 0 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 1 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 2 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 3 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 4 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 5 波数据
...
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 123 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 124 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 125 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 126 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 127 波数据
D/TAG: Flowable创建被观察者 观察者 onNext方法 o.toString()----:Flowable创建被观察者 被观察者发送第 149 波数据
D/TAG: Flowable创建被观察者 观察者 onComplete方法
说明
使用 BackpressureStrategy.LATEST 模式 时 当被观察者发出超出128条数据时 流程正常。输出[0,127]条数据+最后一条数据。
<3> 总结
BackpressureStrategy枚举类的使用,只在被观察者发送的消息数量超过默认缓存量128。才有效果。
<4> 更多RxJava背压讲解
https://blog.youkuaiyun.com/weixin_37730482/article/details/78086361