目录
1.RxJava 3
2.观察者模式组合
3.Flowable(数据源类一)
3.1.Flowable
3.2.BackpressureStrategy背压策略
3.3.响应式拉取(Flowable特有)
3.4.FlowableEmitter(数据发送器)
3.5.背压问题解决方案:(Flowable按需发送数据)
4.Observable(数据源类二)
4.1.Observable
4.2.ConnectableObservable
4.3.refObservable
4.4.autoObservable
5.Observer and Subscriber
JavaDoc
http://reactivex.io/RxJava/3.x/javadoc/
https://github.com/ReactiveX/RxJava/wiki/What's-different-in-3.0
添加依赖
implementation 'io.reactivex.rxjava3:rxjava:3.x.y'
implementation 'io.reactivex.rxjava3:rxandroid:3.x.y'
Java 8(来源于官方文档)
由于Android运行时支持方面的落后,RxJava 长期基于Java 6 API。未来的 Android Studio 4中,一个叫做 desuging 的过程能够将许多Java 7和8的特性,透明地转换成与 Java 6兼容的特性。
So,RxJava3的baseline可以提高到 Java 8,并增加Java 8的官方支持,比如:Optional、Stream等,因此必须将项目的编译目标设置更改为 java8:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
RxJava 3.0遵循Reactive-Streams specification规范。
在RxJava 3中,提供了五对观察者模式组合,每一对组合依靠其可调用的一系列函数的差异,具有各自的特点。
第一组:Observable(ObservableSource)/ Observer
一次可发送单条数据或者数据序列onNext,可发送完成通知onComplete或异常通知onError,不支持背压。
第二组:Publisher(Flowable)/ Subscriber(FlowableSubscriber)
第一组基础上进行改进,发送0到N个的数据(onNext),支持Reactive-Streams和背压,可发送完成通知onComplete或异常通知onError,但效率没有第一组高。
第三组:Single(SingleSource) / SingleObserver
第一组简化版,只能发送单条数据onSuccess,或者异常通知onError
第四组:Completable(CompletableSource)/ CompletableObserver
第一组简化版,不能发送数据,只发送完成通知onComplete或者异常通知onError
第五组:Maybe(MaybeSource) / MaybeObserver
第三,第四组的合并版,只能发送单条数据onSuccess和完成通知onComplete或者发送一条异常通知onError
Flowable是RxJava2.x中新增的,专门用于应对背压(Backpressure)问题,在Observable的基础上优化后的产物。
Observable ——> subscribe() ——> Observer
Flowable ——> subscribe() ——> Subscriber
后者是前者针对背压问题的优化产物,前者运行效率更高,后者支持背压问题处理,但逻辑更多,运行效率稍低,速度稍慢。
Flowable数据流程:Flowable ——> 异步缓存池(128)——> Subscriber
Flowable默认异步缓存队列大小为128。作用是缓存当前未来得及处理(Subscriber未接收,或者由于某种原因,Flowable未实际发送给Subscriber)的数据。也就是说随着Subscriber对数据的接收处理,缓存池也会随之做清理更新:去掉已经被Subscriber接收的,塞进Flowable新发送的。
注意:并不是Subscriber接收一条,便清理一条,而是存在一个延迟,等累积一段时间后统一清理一次。
所以:当生产者和消费者在相同的线程中;或者当生产者和消费者在不同线程中,但消费者消费数据的速度不低于生产者发送数据的速度,或者整条数据流中只有一条数据时 …… 使用Observable会更好。
Flowable
.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter e) throws Exception {
System.out.println("发送----> 1");
e.onNext(1);
System.out.println("发送----> 2");
e.onNext(2);
System.out.println("发送----> 3");
e.onNext(3);
System.out.println("发送----> 完成");
e.onComplete();
}
}, BackpressureStrategy.BUFFER) //指定背压处理策略:缓存
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE); // 响应式拉取
}
@Override
public void onNext(Integer integer) {
System.out.println("接收----> " + integer);
}
@Override
public void onError(Throwable t) {}
@Override
public void onComplete() {
System.out.println("接收----> 完成");
}
});
注意:
(1)BackpressureStrategy.BUFFER设置背压处理策略
(2)Subscription区别于Observer的Disposable
(3)发送器FlowableEmitter,不同于Observable的ObservableEmitter
Flowable本身适用于异步场景,内置默认上限128的异步缓存池,用于缓存当前未来得及处理(Subscriber未接收或者由于某种原因Flowable未实际发送给Subscriber)的数据。BackpressureStrategy的作用便是用来设置Flowable通过异步缓存池缓存数据的策略。
RxJava 3针对不同的五种策略(MISSING,ERROR,DROP,LATEST,BUFFER)内置了相应的数据发送器类,系统通过代理模式对五种数据发送器做了包装(FlowableCreate.java中实现)。
public void subscribeActual(Subscriber super T> t) {
BaseEmitter emitter;
switch (backpressure) {
case MISSING: {
emitter = new MissingEmitter(t);
break;
}
case ERROR: {
emitter = new ErrorAsyncEmitter(t);
break;
}
case DROP: {
emitter = new DropAsyncEmitter(t);
break;
}
case LATEST: {
emitter = new LatestAsyncEmitter(t);
break;
}
default: {
emitter = new BufferAsyncEmitter(t, bufferSize());
break;
}
}
t.onSubscribe(emitter);
// ......
}
MISSING(MissingEmitter
策略:无特定背压处理策略,对数据无缓存和丢弃的处理,需结合创建背压操作符确定背压策略。
背压操作符:
onBackpressureBuffer() 对应BackpressureStrategy.BUFFER
onBackpressureDrop() 对应BackpressureStrategy.DROP
onBackpressureLatest() 对应BackpressureStrategy.LATEST
static final class MissingEmitter extends FlowableCreate.BaseEmitter {
// ......
@Override
public void onNext(T t) {
if (isCancelled()) {
return;
}
if (t != null) {
actual.onNext(t);
} else {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
for (; ; ) {
long r = get();
if (r == 0L || compareAndSet(r, r - 1)) {
return;
}
}
}
}
ERROR(ErrorAsyncEmitter
策略:Flowable异步缓存池超限(onOverflow()),直接扔异常MissingBackpressureException,缓存池上限128。
static final class ErrorAsyncEmitter extends NoOverflowBaseAsyncEmitter {
private static final long serialVersionUID = 338953216916120960L;
ErrorAsyncEmitter(Subscriber super T> actual) {
super(actual);
}
@Override
void onOverflow() {
onError(new MissingBackpressureException("create: could not emit value due to lack of requests"));
}
}
DROP(DropAsyncEmitter
策略:Flowable的异步缓存池满了,直接丢掉后续发送的数据。
static final class DropAsyncEmitter extends NoOverflowBaseAsyncEmitter {
private static final long serialVersionUID = 8360058422307496563L;
DropAsyncEmitter(Subscriber super T> actual) {
super(actual);
}
@Override
void onOverflow() {// nothing to do}
}
onOverflow()方法 do nothing!很明显处理逻辑在其父类NoOverflowBaseAsyncEmitter,查看代码逻辑,发现在调用actual.onNext(t);之前做了get() != 0的判断,意思就是说缓存超限,什么也不做,不超限才发送数据。也就是说如果Flowable的异步缓存池满了,会丢掉后续由上层发送的数据(FlowableEmitter
@Override
public final void onNext(T t) {
if (isCancelled()) {
return;
}
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
if (get() != 0) {
actual.onNext(t);
BackpressureHelper.produced(this, 1);
} else {
onOverflow();
}
}
LATEST(LatestAsyncEmitter
策略:Flowable的异步缓存池满了,直接丢掉后续发送的数据。但会保证最后一条数据强制缓存,并保证发送,通过内置final AtomicReference
代码比较复杂,分析略!
BUFFER(BufferAsyncEmitter
策略:通过内置
final SpscLinkedArrayQueue<T> queue;
缓存所有超限数据,该策略不会抛出MissingBackpressureException异常,不会丢失数据(在内置缓存大小范围内),但会导致OOM。
SpscLinkedArrayQueue内部实现为数组,大小默认128,当缓存数超过128,SpscLinkedArrayQueue会重新分配缓存空间,简而言之,这是一个无限大的缓存池。
static final class BufferAsyncEmitter extends BaseEmitter {
// ......
final SpscLinkedArrayQueue queue;
BufferAsyncEmitter(Subscriber super T> actual, int capacityHint) {
super(actual);
this.queue = new SpscLinkedArrayQueue(capacityHint);
this.wip = new AtomicInteger();
}
@Override
public void onNext(T t) {
// ......
queue.offer(t);
// ......
}
// ......
}
Subscription接口定义了两个方法:
void cancel(); 取消Subscriber与Flowable的订阅关系。
void request(long n); 声明并控制订阅者对Publisher数据的需求量。
Flowable在设计的时候,采用了一种新的思路——响应式拉取方式,来设置订阅者对数据的请求数量,Flowable可以根据订阅者的需求量,按需发送数据。
如果不显式调用Subscription.request(Long)则默认订阅者的需求量为零,所以如果Subscriber不显示调用request方法,Flowable发送的数据并不会交给Subscriber处理。
Subscription.request(Long)可多次调用,Subscriber总共获取的数据量是多次调用累计之和(不大于Flowable发出的数据量),如果Subscriber请求的数据量小于Flowable发送的数据量,那么需求之外的数据仍然放到了异步缓存池中。如果异步缓存池超限,会导致MissingBackpressureException异常。
当Subscription.request(0)时,报错:java.lang.IllegalArgumentException: n > 0 required but it was 0
响应式拉取的初衷,是为了设置订阅者对数据的请求数量,Flowable可以根据订阅者的需求量,按需发送数据。
FlowableEmitter可以实现这一需求,FlowableEmitter内置long requested();可以获取当前Flowable未完成的请求数量。随着Flowable不停发送数据,long requested();值会相应变化。
public interface FlowableEmitter extends Emitter {
void setDisposable(@Nullable Disposable s);
void setCancellable(@Nullable Cancellable c);
long requested();
boolean isCancelled();
@NonNull
FlowableEmitter serialize();
@Experimental
boolean tryOnError(@NonNull Throwable t);
}
重点关注long requested();方法!
同步状态下:
FlowableEmitter.requested();方法获取到的最大未完成请求数 == Subscriber 中Subscription.request(Long)中请求的数量,与Flowable缓存队列大小无关。
FlowableEmitter.requested();的实时值 = Subscription.request(Long)中请求的数量 – Flowable已经发送的数量。
异步状态下:
FlowableEmitter.requested();方法获取到的最大未完成请求数 == 128;等于Flowable缓存队列大小,与Subscriber 中Subscription.request(Long)中请求多少无关。
Flowable有一个异步缓存池,Flowable发送的数据,先放到异步缓存池中,再由异步缓存池交给Subscriber。所以Flowable在发送数据时,首先需要考虑的不是Subscriber的数据请求量,而是缓存池中能不能放得下,放得下直接塞入,放不下执行背压策略。至于是否超出了Subscriber的数据需求量,可以在缓存池向其传递数据时,再作判断,如果未超出,则将缓存池中的数据传递,如果超出了,则不传递。
FlowableEmitter.requested();的实时值 = Flowable异步缓存池当前可用空间大小。并不是下游真正的数据请求数量!
随着缓存池把数据发送给Subscriber,Flowable将执行清理缓存的策略,异步缓存池中的数据并不是向Subscriber发送一条便清理一条,而是每等累积到N条时,清理一次。通过e.requested()获取到的值,正是在异步缓存池清理数据时回升的。也就是异步缓存池每次清理后,都会导致Flowable未完成请求数量的回升,理想状态下,缓存池在Flowable发送数据时一直有空间,这样既不会引发背压异常,也不会导致数据遗失。
例如:
1.Flowable有N条数据(N ≤ 128),Subscription.request(M)(M < N)
Flowable实际发送N条数据到异步缓存池,再由异步缓存池发送M条数据给Subscriber。
2.Flowable有N条数据(N ≤ 128),Subscription.request(M)(M ≥ N)
Flowable实际发送N条数据到异步缓存池,再由异步缓存池发送N条数据给Subscriber。
3.Flowable有N条数据(N > 128),Subscription.request(M)(M ≤ 128)
Flowable实际发送K(N ≥ K ≥ 128,K的具体数量和Subscriber接收处理数据的速度有关)条数据到异步缓存池,其余部分执行背压策略,再由异步缓存池发送M条数据给Subscriber。
4.Flowable有N条数据(N > 128),Subscription.request(M)(M > 128)
Flowable实际发送K(N ≥ K ≥ 128,K的具体数量和Subscriber接收处理数据的速度有关)条数据到异步缓存池,其余部分执行背压策略,再由异步缓存池发送M(M < K) / K(M ≥ K)条数据给Subscriber。
注意:onComplete(),onError()并不减少requested值。
如果由于订阅者处理数据缓慢,导致Flowable异步缓存池被塞满且无法得到清理,通过requested()获取的值也就变成了0,会根据BackpressureStrategy背压策略的不同,抛出MissingBackpressureException异常,或做额外缓存或者丢掉这条数据。所以Flowable只需要在e.requested()等于0时,暂停发送数据,便可解决背压问题!!!
完整方案:
发送方按需发送;
@Override
public void subscribe(FlowableEmitter e) throws Exception {
int i = 0;
while (true) {
if (e.requested() == 0) continue; //此处添加代码,让flowable按需发送数据
System.out.println("发送---->" + i);
i++;
e.onNext(i);
}
}
接收方处理一条再请求下一条;
private Subscription mSubscription;
@Override
public void onSubscribe(Subscription s) {
s.request(1); // 设置初始请求数据量为1
mSubscription = s;
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(50);
System.out.println("接收------>" + integer);
mSubscription.request(1);// 每接收到一条数据增加一条请求量
} catch (InterruptedException ignore) {
}
}
Observable:抽象类Observable是接口ObservableSource的一个抽象实现,我们可以通过Observable创建一个可观察对象发送数据流。
// 发送对应的方法
Observable.create(new ObservableOnSubscribe() {
// 默认在主线程里执行该方法
@Override
public void subscribe(@NonNull ObservableEmitter e) throws Exception {
e.onNext("Hello");
e.onNext("World");
// 结束标识
e.onComplete();
}
});
ObservableEmitter:数据发送器
public interface Emitter {
void onNext(@NonNull T value);
void onError(@NonNull Throwable error);
void onComplete();
}
(1)onNext:用来发送数据,可多次调用,每调用一次发送一条数据
(2)onError:用来发送异常通知,只发送一次,若多次调用只发送第一条
(3)onComplete:用来发送完成通知,只发送一次,若多次调用只发送第一条
onError与onComplete互斥,两个方法只能调用一个不能同时调用!
接口Observer中的三个方法(onNext,onError,onComplete)正好与Emitter中的三个方法相对应,分别对Emitter中对应方法的行为作出响应。
Emitter调用onNext发送数据时,Observer会通过onNext接收数据。
Emitter调用onError发送异常通知时,Observer会通过onError接收异常通知。
Emitter调用onComplete发送完成通知时,Observer会通过onComplete接收完成通知。
Observable 在2.0中被设计成了无处理背压能力的,避免了1.0中出现的Observable不能合理背压,导致无法预料的MissingBackpressureException出现。
参数对象ObservableOnSubscribe会被存储在返回的 Observable 对象中,它的作用相当于一个计划表,当 Observable 被订阅的时候,ObservableOnSubscribe的 subscribe () 方法会自动被调用,事件序列就会依照设定依次触发(ObservableEmitter将会被调用2次 onNext() 和1次 onComplete())。这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即观察者模式。
通过Observable.create、Observable.interval等创建型操作符生成的Observable。
(1)当一个订阅者订阅Observable(包括重复订阅)时,Observable会重新开始发送数据给订阅者。
(2)当多个订阅者订阅到同一个Observable时,订阅者收到的数据是相互独立的。
(3)(2)情况下,当其中一个订阅者取消订阅,Observable只会停止对该订阅者的数据发送。
ConnectableObservable通过Observable.publish();Observable.reply(int N) 转换生成。publish():订阅者订阅ConnectableObservable只能收到订阅行为以后数据源发送的数据;replay(int N):订阅者订阅ConnectableObservable能收到订阅行为之前发送的N个数据。
(1)无论ConnectableObservable有没有订阅者,只要调用了ConnectableObservable的connect方法,原始Observable就开始发送数据。
(2)connect返回一个Disposable对象,调用了该对象的dispose方法,原始Observable将会停止发送数据,所有ConnectableObservable的订阅者也无法收到数据。
(3)在调用connect返回的Disposable对象后,如果重新调用了connect方法,那么原始Observable会重新发送数据。
(4)当多个订阅者订阅同一个ConnectableObservable时,它们收到的数据是相同的。
(5)当一个订阅者取消对ConnectableObservable,不会影响其他订阅者收到消息。
(6)多个订阅者订阅ConnectableObservable,真正原始属于源并不知道订阅者的存在,和订阅者交互的实际是ConnectableObservable,起到一个承上启下的中介作用。
refObservable指的是由ConnectableObservable通过.refCount() 转换而来的Observable;或者由Observable.share()方法转换成的Observable。
(1)当第一个订阅者订阅refObservable后,原始Observable开始发送数据。
(2)之后的订阅者订阅到refObservable后,只能接收到订阅之后,原始Observable 发送的数据。
(3)(2)情况下,如果一个订阅者取消订阅refObservable,不影响其他订阅者接收数据;如果全部订阅者都取消了订阅,则原始Observable停止发送数据。
autoObservable由ConnectableObservable通过.autoConnect(int N)转换而来的特殊Observable:
(1)当有N个订阅者订阅autoObservable后,原始Observable开始发送数据。
(2)只要原始Observable开始发送数据,即使所有的订阅者都取消了对autoObservable的订阅,原始Observable也不会停止发送数据。
// 创建被观察者
Observable.just("Hello", "World")
// 将被观察者切换到子线程
.subscribeOn(Schedulers.io())
// 将观察者切换到主线程
.observeOn(AndroidSchedulers.mainThread())
// 创建观察者并订阅
.subscribe(new Observer() {
// Disposable 相当于RxJava1.x中的 Subscription,用于解除订阅
private Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(String s) {
Log.i("JAVA", "被观察者向观察者发送的数据:" + s);
if (s == "-1") { // "-1" 时为异常数据,解除订阅
disposable.dispose();
}
}
@Override
public void onError(Throwable e) {}
@Override
public void onComplete() {}
});
订阅做了以下几件件事:
(1)首先调用onSubscribe()方法
(2)其次调用ObservableOnSubscribe的subscribe方法,事件发送的逻辑由这里开始运行,之后针对性地调用Observer相应方法进行数据响应。
另外,直接订阅或传入消费者会产生一个新的类:Disposable,用于取消订阅。Observable在订阅取消之后发送的数据,Observer将不会接收。
简化订阅:上面Observer可以通过Consumer(Consumer就是消费者的意思,替代1.0的Action0,Action1),来消费onSubscribe,onNext,onComplete,onError等事件:
RxJava 3中没有了一系列的Action/Func接口,取而代之的是与Java8命名类似的函数式接口。Action类似于RxJava1.x中的Action0,区别在于Action允许抛出异常;Consumer即消费者,用于接收单个值,BiConsumer则是接收两个值,Function用于变换对象Function的泛型第一个为接收参数的数据类型,第二个为转换后要发送的数据类型,Predicate用于判断。这些接口命名大多参照了Java8。
Observable.just("Hello", "World")
.subscribe(new Consumer() {
@Override
public void accept(@NonNull String s) throws Exception {
//这里接收数据(onNext)。
Log.i("JAVA", "被观察者向观察者发送的数据:" + s);
}
}, new Consumer() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
//这里接收异常Throwable。
}
}, new Action() {
@Override
public void run() throws Exception {
//这里接收onComplete。
}
}, new Consumer() {
@Override
public void accept(@NonNull Disposable disposable) throws Exception {
//这里相当于onSubscribe。
}
});