先来一个Jack大神的演讲视频
Managing the Reactive World with RxJava
Backpressue
Backpressue是指一个Flowable管道处理中,有些异步状态无法及时处理产出的值,需要一种方式来告诉upstream降低生产数据的节奏,本质上是一种flow control策略。
如下例子,source产出了过多的数据,会导致downstream处理不及时而导致问题
PublishProcessor<Integer> source = PublishProcessor.create();
source
.observeOn(Schedulers.computation())
.subscribe(v -> compute(v), Throwable::printStackTrace);
for (int i = 0; i < 1_000_000; i++) {
source.onNext(i);
}
Thread.sleep(10_000);
使用如下写法,则不会有任何问题
Flowable.range(1, 1_000_000)
.observeOn(Schedulers.computation())
.subscribe(v -> compute(v), Throwable::printStackTrace);
Thread.sleep(10_000);
在Rxjava3里面,提供了5种处理策略,定义在BackpressureStrategy里面
- MISSING onNext事件没有任何buffer缓存,或丢弃,downstream必须处理这些overflow.适用场景:
- ERROR 发送一个MissingBackpressureException以防止downstream无法继续处理
- BUFFER 缓存所有onNext值到downstream消费,默认Buffer大小是128,可以修改
- DROP 如果downstream无法处理,丢弃最近的onNext事件
- LATEST 仅保存最新的onNext值,如果downstream无法处理,则覆写先前的值
具体实现的类图结构如下:
onBackpressureXXX操作
大部分开发者遇到backpressure是当应用出问题抛出MissingBackpressureException异常,而且异常通常指向于observeOn操作上。
实际的原因是使用了不支持backpressure的PublishProcessor、timer()、interval、或者通过create自定义的操作
有几种方式可以处理此场景:
- 增加buffer的大小
有时overflow是因为快速的事件产生。用户突然快速点击屏幕,observeOn在android默认大小是16
在最新的Rxjava里面,开发者可以显式的指定缓存大小,相关的参数
Flowable.range(1, 1_000_000)
.onBackpressureBuffer(1024)
然而在通常场景下,只设置一个临时的大小也会出现overflow的情况,当源数据生产了超出预测缓存大小时,在这种场景下,可以使用如下操作
- onBackPressureBuffer系列方法
传入的参数都不同,最终都是创建FlowableOnBackpressureBuffer
- final int bufferSize 缓存大小
- final boolean unbounded 如果为true,表示缓存大小被解释为内部无界缓存的island值
- final boolean delayError 如果为true,表示一个Flowable里面的exception会延迟发送,直到缓存里面的所有元素都被downstream消费掉;为false时,会直接将Excetion通知到downstream,忽略缓存的数据
- final Action onOverflow 当一个事件需要被缓存,但是没有空间的时候,会执行此aciton
其中unbounded生效的场景为
if (unbounded) {
q = new SpscLinkedArrayQueue<>(bufferSize); // 可以调整大小
} else {
q = new SpscArrayQueue<>(bufferSize); // 大小固定
}
- onBackPressureDrop
如果downstream还没有准备好接收新的事件(通过Subscription.request调用的缺失来表示);从当前Flowable里面丢弃.
如果downstream request为0,则由此产生的Flowable将不调用onNext,直到Subscriber再次调用request(n)来增加请求计数。
参数Consumer<? super T> onDrop 表示针对每个drop的事件,都会执行此action,应该快速且非阻塞
对应的实现策略在FlowableOnBackpressureDrop文件里面
- onBackpressureLatest
如果downstream还没有准备好接收新的事件(通过Subscription.request调用的缺失来表示);从当前Flowable里面丢弃除最新之外的事件,当downstream准备好的时候,把最新的事件发给downstream
具体的实现是在FlowableOnBackpressureLatest类里面
backpressured 数据源的创建方式
- **Flowable.just **
返回一个Flowable,然后把给定的常量引用事件发送出去,然后结束。注意这个事件被获取,然后重新发送,just不会改这个事件。使用fromCallable近需来生成单个事件
一个简单的例子:
Flowable.just(5).subscribe(new DisposableSubscriber<Integer>() {
@Override
public void onStart() {
request(2);
}
@Override
public void onNext(Integer v) {
System.out.println(v);
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
}
输出为如下,request里面的数字没有影响到onComplete的调用:
5
onComplete
具体实现类为FlowableJust
@Override
public void request(long n) {
// n 要求大于等于0
if (!SubscriptionHelper.validate(n)) {
return;
}
if (compareAndSet(NO_REQUEST, REQUESTED)) {
Subscriber<? super T> s = subscriber;
// 把事件发送给订阅者
s.onNext(value);
if (get() != CANCELLED) {
// 发送完成事件
s.onComplete();
}
}
}
当just方法里面有多个参数的时候,内部实现是通过formarray
public static <@NonNull T> Flowable<T> just(T item1, T item2) {
Objects.requireNonNull(item1, "item1 is null");
Objects.requireNonNull(item2, "item2 is null");
return fromArray(item1, item2);
}
- Flowable.fromCallable
返回一个Flowable,当一个Subscriber订阅的时候,会调用指定的Callable,然后返回Callable的执行结果并作为事件发送出去
此方法可以指定直到一个Subscriber订阅Publisher时,才执行特定的方法,换句话说,可以延迟加载
Flowable<Integer> o = Flowable.fromCallable(() -> computeValue());
具体实现类为FlowableFromCallable
public void subscribeActual(Subscriber<? super T> s) {
DeferredScalarSubscription<T> deferred = new DeferredScalarSubscription<>(s);
s.onSubscribe(deferred);
T t;
try {
// 执行callable.call方法
t = Objects.requireNonNull(callable.call(), "The callable returned a null value");
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
if (deferred.isCancelled()) {
RxJavaPlugins.onError(ex);
} else {
s.onError(ex);
}
return;
}
// 将执行结果发送出去
deferred.complete(t);
}
public final void complete(T v) {
int state = get();
for (;;) {
if (state == FUSED_EMPTY) {
value = v;
lazySet(FUSED_READY);
Subscriber<? super T> a = downstream;
// 把事件发送给订阅者
a.onNext(v);
if (get() != CANCELLED) {
// 发送完成事件
a.onComplete();
}
return;
}
// if state is >= CANCELLED or bit zero is set (*_HAS_VALUE) case, return
if ((state & ~HAS_REQUEST_NO_VALUE) != 0) {
return;
}
if (state == HAS_REQUEST_NO_VALUE) {
lazySet(HAS_REQUEST_HAS_VALUE);
Subscriber<? super T> a = downstream;
a.onNext(v);
if (get() != CANCELLED) {
a.onComplete();
}
return;
}
value = v;
if (compareAndSet(NO_REQUEST_NO_VALUE, NO_REQUEST_HAS_VALUE)) {
return;
}
state = get();
if (state == CANCELLED) {
value = null;
return;
}
}
}
- Flowable.fromArray
把一个数组转换成一个Publisher,然后发送数组里面的每个元素,当数组长度为1时,等效于just方法
public static <@NonNull T> Flowable<T> fromArray(@NonNull T... items) {
Objects.requireNonNull(items, "items is null");
if (items.length == 0) {
return empty();
}
if (items.length == 1) {
return just(items[0]);
}
return RxJavaPlugins.onAssembly(new FlowableFromArray<>(items));
}
一个简单的例子
Flowable.fromArray(1, 2, 3, 4, 5).subscribe(System.out::println);
具体实现类为FlowableFromArray
public final void request(long n) {
if (SubscriptionHelper.validate(n)) {
if (BackpressureHelper.add(this, n) == 0L) {
if (n == Long.MAX_VALUE) {
fastPath();
} else {
slowPath(n);
}
}
}
}
void slowPath(long r) {
long e = 0;
T[] arr = array;
int f = arr.length;
int i = index;
Subscriber<? super T> a = downstream;
for (;;) {
while (e != r && i != f) {
if (cancelled) {
return;
}
T t = arr[i];
if (t == null) {
a.onError(new NullPointerException("The element at index " + i + " is null"));
return;
} else {
// 循环发送事件给downstream
a.onNext(t);
}
e++;
i++;
}
if (i == f) {
if (!cancelled) {
// 数组事件都发送完后,
a.onComplete();
}
return;
}
r = get();
if (e == r) {
index = i;
r = addAndGet(-e);
if (r == 0L) {
return;
}
e = 0L;
}
}
}
fromIterable 实现fromarrsy类似,FlowableFromIterable可以用来实现状态机
Iterable<Integer> iterable = () -> new Iterator<Integer>() {
@Override
public boolean hasNext() {
return true;
}
@Override
public Integer next() {
return 1;
}
};
Flowable.fromIterable(iterable).take(5).subscribe(System.out::println);
- Flowable.generate
有时,数据源是同步的(blocking)和push的方式,被转换成响应式时,我们调用get或read方法来获取下数据源中的下一块。当然,可以使用Iterable,但是当源和某些资源关联时,当downstream在资源关闭前停止订阅的时, 可能会导致资源泄露
在RxJava里面,处理这些场景,提供了generate工厂方法族
通常,generate使用3个callback
- 第一个callback 使用Supplier为每个Subscriber创建一个初始化状态
- 第二个callback 获取state对象,然后提供一个输出Observer,onXXX方法可以被调用来发送事件。这个回调会执行downstream的request,最多只能调用onNext一次,可选后跟onError或onComplete
- 第三个callable,处理downstream,即当前generator结束序列或被取消时,Consumer来处理后续的
方法的定义如下:
* @param initialState the {@link Supplier} to generate the initial state for each {@code Subscriber}
* @param generator the {@link Consumer} called with the current state whenever a particular downstream {@code Subscriber} has
* requested a value. The callback then should call {@code onNext}, {@code onError} or
* {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext}
* in a call will make the operator signal {@link IllegalStateException}.
* @param disposeState the {@code Consumer} that is called with the current state when the generator
* terminates the sequence or it gets canceled
public static <T, S> Flowable<T> generate(@NonNull Supplier<S> initialState, @NonNull BiConsumer<S, Emitter<T>> generator,
@NonNull Consumer<? super S> disposeState) {
Objects.requireNonNull(generator, "generator is null");
return generate(initialState, FlowableInternalHelper.simpleBiGenerator(generator), disposeState);
}
unsubscribe事件或前一个callback的结束事件,可以在这个里面释放资源
一个简单的例子
Flowable<Integer> o = Flowable.generate(
() -> new FileInputStream("data.bin"),
(inputstream, output) -> {
try {
int abyte = inputstream.read();
if (abyte < 0) {
output.onComplete();
} else {
output.onNext(abyte);
}
} catch (IOException ex) {
output.onError(ex);
}
return inputstream;
},
inputstream -> {
try {
inputstream.close();
} catch (IOException ex) {
RxJavaPlugins.onError(ex);
}
}
);
对应的实现类是FlowableGenerate
从JVM和lib库里面很多方法调用,会跑出checked exception,需要用try/catch包起来,此类中的函数接口不支持抛出checked exception
- Flowable.create(emitter)
有时,数据源被封装成Flowable的时候,里面的API不支持backpressure(如异步网络请求)。Rxjava里面提供了create(emitter)工厂方法,包含2个参数 - 一个callback,该回调将针对每个传入的subscriber调用Emitter接口
- 一个BackpressureStrategy策略,同onBackpressureXXX类似
当前不支持非BackpressureStrategy之外的策略
Emitter使用起来很简单,直接调用其onNext/onError/onComplete
具体的实现类是FlowableCreate ,看一个简单的例子
Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull FlowableEmitter<String> emitter) throws Throwable {
System.out.println("Publisher subscribe = " + Thread.currentThread().getName());
emitter.onNext("Hello");
emitter.onNext("World");
emitter.onComplete();
}
}, BackpressureStrategy.BUFFER);
具体的调用过程,在RxJava分析系列之RxJava实现原理分析part1 里面的
2.观察者模式的实现
数据支持的操作
创建方式
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Creating-Observables.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Phantom-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Subject.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/String-Observables.md
支持的操作
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Conditional-and-Boolean-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Filtering-Observables.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Connectable-Observable-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Combining-Observables.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Mathematical-and-Aggregate-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Blocking-Observable-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Operator-Matrix.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Parallel-flows.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Async-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Observable-Utility-Operators.md
错误处理
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Error-Handling-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Error-Handling.md
自定义操作
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Implementing-Your-Own-Operators.md
- https://github.com/ReactiveX/RxJava/blob/3.x/docs/Plugins.md