1.概述
关于RxJava2.0与1.x区别的详细介绍,参考官方文章:https://github.com/ReactiveX/RxJava/wiki/What%27s-different-in-2.0
当被观察者发出事件的速度快于观察者处理事件的速度时(不妨称呼这种现象为“流量过大”),未被及时处理的事件会被缓存在内存中等待处理。如果这种状况得不到改善的话,随着时间的推移,堆积在内存中的待处理事件会越来越多,程序的内存占用会越来越高,最终结果就是导致内存溢出(OOM)和程序崩溃。
背压(backpressure)是解决“流量过大”问题的手段之一(背压的具体信息后面会介绍)。
在RxJava1.x中,支持背压和不支持背压的被观察者都是Observable,对于使用者而言,很容易混淆和误用。而RxJava2.0与RxJava1.x相比最大区别就是,引入了一个新的基类Flowable用以表示支持背压的被观察者,并且Observable的代码也被重写,用以表示不支持背压的被观察者,简单的说就是:Flowable——支持背压,Observable——不支持背压。
2.类与方法概览
根据是否支持背压,RxJava2.0中的类可以被大致划分为两个体系:Flowable-Subscriber体系 和 Observable-Observer体系,如下所示。大致了解一下即可,下一小节会有详细的使用示例和解释。
Observer用于订阅Observable,而Subscriber用于订阅Flowable(及其他Publisher的实现类)。
Observable-Observer体系(不支持背压)
Observable<T> implements ObservableSource<T>{...}
public interface ObservableSource<T> {
void subscribe(Observer<? super T> observer);
}
//Observer用于订阅Observable
public interface Observer<T> {
//当订阅(subscribe)发生时被调用,在此方法中可以获得Disposable对象(用以取消订阅关系)
//Provides the Observer with the means of cancelling (disposing) the connection (channel) with the Observable in both synchronous (from within onNext(Object)) and asynchronous manner.
//d:the Disposable instance whose Disposable.dispose() can be called anytime to cancel the connection
void onSubscribe(Disposable d);
void onNext(T t);
void onError(Throwable e);
void onComplete();
}
//用以取消订阅关系(dispose方法)
public interface Disposable {
//取消当前Observer和Observable之间的订阅关系
void dispose();
boolean isDisposed();
}
Flowable-Subscriber体系(支持背压)
除了是否支持背压之外,Flowable与Observable还有一个区别,就是:Flowable发出事件之后,事件并不直接发送给观察者Subscriber(即便此时Subscriber是空闲的),而是将事件缓存在内存中,只有当调用了subscription.request(n)之后,事件才会被发送给观察者Subscriber。
Flowable<T> implements Publisher<T>{...}
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
//Subscriber用于订阅Flowable(及其他Publisher的实现类)
public interface Subscriber<T> {
//当订阅(subscribe)发生时被调用,在此方法中可以获得Subscription对象
//Invoked after calling Publisher.subscribe(Subscriber).
//No data will start flowing until Subscription.request(long) is invoked.
//It is the responsibility of this Subscriber instance to call Subscription.request(long) whenever more data is wanted.
//The Publisher will send notifications only in response to Subscription.request(long).
void onSubscribe(Subscription s);
void onNext(T t);
void onError(Throwable t);
void onComplete();
}
//有两个功能:1.请求Flowable发出事件(request方法) 2.取消订阅关系(cancel方法)
public interface Subscription {
//请求Flowable发出事件
public void request(long n);
//取消当前Subscriber与Flowable的订阅关系
//Request the Publisher to stop sending data and clean up resources.
//Data may still be sent to meet previously signalled demand after calling cancel.
public void cancel();
}
3 使用示例
3.1 基本使用
Observable-Observer体系:
可以发现,使用方式与RxJava1.x基本一样,只是细节上有一点区别。
Observable
.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onComplete();
}
})
.subscribe(new Observer<Integer>() {
//当订阅(subscribe)发生时被调用,Disposable对象用来取消订阅关系(dispose方法)
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Integer integer) {
Log.e("log", "处理:" + integer);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
Flowable-Subscriber体系:
因为Flowable支持背压,因此在通过create创建Flowable对象的时候,需要传入一个背压策略参数(BackpressureStrategy,后面详细说)。
此外,Subscriber需要调用Subscription的request方法,才能获取到Flowable发出的事件。
Flowable
.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onComplete();
}
}, BackpressureStrategy.BUFFER)
.subscribe(new Subscriber<Integer>() {
Subscription subscription;
//当订阅(subscribe)发生时被调用
//Subscription对象可以用来请求Flowable发出事件(request方法),以及取消订阅关系(cancel方法)
@Override
public void onSubscribe(Subscription s) {
subscription = s;
subscription.request(1);//先获取一个事件,这样onNext才能接收到第一个事件
}
@Override
public void onNext(Integer integer) {
Log.e("log", "处理:" + integer);
subscription.request(1);//获取下一个事件
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
3.2 简化代码
同RxJava1.x类似,RxJava2.0也提供了一系列fromXXX(…)和just(…)方法用来简化被观察者的创建。以Flowable为例,让我们简单看看这两类方法都有哪些重载:
fromArray(T... items)
fromCallable(Callable<? extends T> supplier)
fromFuture(...)
fromIterable(Iterable<? extends T> source)
fromPublisher(Publisher<? extends T> source)
just(T item)
just(T item1, T item2)
...
just(T item1, T item2, T item3, T item4, T item5, T item6, T item7, T item8, T item9, T item10)
Flowable的subscribe方法也有众多重载,用来简化Subscriber的创建:
subscribe(Consumer<? super T> onNext)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Subscription> onSubscribe)
其中:
public interface Consumer<T> {
void accept(T t) throws Exception;
}
public interface Action {
void run() throws Exception;
}
Consumer其实就是RxJava1.x中的Action1,即对单参数无返回值的函数的封装,只是换了个名字而已。而Action其实就是RxJava1.x中的Action0,即对无参数无返回值的函数的封装。
有了上面这些方法,之前关于Flowable-Subscriber的示例代码就可以简化成这样:
Flowable.just(1, 2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.e("log", "处理:" + integer);
}
});
输出:
E/log: 处理:1
E/log: 处理:2
4 背压详解
4.1 Observable-Observer体系
事件发送与处理在同一线程
Observable
.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
for (int i = 1; i < 10; i++) {
Log.e("log", "发送:" + i);
e.onNext(i);
SystemClock.sleep(100);
}
Log.e("log", "发送:onComplete");
e.onComplete();
}
})
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Integer integer) {
Log.e("log", "处理:" + integer);
SystemClock.sleep(1000);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("log", "处理:onError——" + e.toString());
}
@Override
public void onComplete() {
Log.e("log", "处理:onComplete");
}
});
输出:
E/log:发送:1
E/log:处理:1
E/log:发送:2
E/log:处理:2
E/log:发送:3
E/log:处理:3
E/log:发送:4
E/log:处理:4
E/log:发送:5
E/log:处理:5
E/log:发送:6
E/log:处理:6
E/log:发送:7
E/log:处理:7
E/log:发送:8
E/log:处理:8
E/log:发送:9
E/log:处理:9
E/log:发送:onComplete
E/log:处理:onComplete
当事件发送与处理在同一线程时,遵循发送一个,处理一个,再发送一个,再处理一个……这样的规律。这是由单线程和函数调用关系决定的(参考源码)。
事件发送与处理在不同线程
Observable
.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
for (int i = 1; i < 10; i++) {
Log.e("log", "发送:" + i);
e.onNext(i);
SystemClock.sleep(100);
}
Log.e("log", "发送:onComplete");
e.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Integer integer) {
Log.e("log", "处理:" + integer);
SystemClock.sleep(1000);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("log", "处理:onError——" + e.toString());
}
@Override
public void onComplete() {
Log.e("log", "处理:onComplete");
}
});
输出:
E/log:发送:1
E/log:处理:1
E/log:发送:2
E/log:发送:3
E/log:发送:4
E/log:发送:5
E/log:发送:6
E/log:发送:7
E/log:发送:8
E/log:发送:9
E/log:发送:onComplete
E/log:处理:2
E/log:处理:3
E/log:处理:4
E/log:处理:5
E/log:处理:6
E/log:处理:7
E/log:处理:8
E/log:处理:9
E/log:处理:onComplete
可见,由于事件发出和处理不在同一线程,因此二者互不影响。事件的发出速度是处理速度的十倍,得不到及时处理的事件就会被缓存在内存中。本例中只有10个事件,因此并不足以造成什么严重后果,但如果事件非常多呢?越来越多的事件因得不到及时处理而堆积在内存中,最终势必会造成内存溢出(OOM)。
4.2 Flowable-Subscriber体系
事件发送与处理在不同线程
Flowable
.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {
for (int i = 1; i < 10; i++) {
Log.e("log", "发送:" + i);
e.onNext(i);
SystemClock.sleep(100);
}
Log.e("log", "发送:onComplete");
e.onComplete();
}
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Integer>() {
Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
subscription = s;
subscription.request(1);
}
@Override
public void onNext(Integer integer) {
Log.e("log", "处理:" + integer);
SystemClock.sleep(1000);
subscription.request(1);
}
@Override
public void onError(Throwable t) {
Log.e("log", "处理:onError——" + t.toString());
}
@Override
public void onComplete() {
Log.e("log", "处理:onComplete");
}
});
输出:
E/log: 发送:1
E/log: 处理:1
E/log: 发送:2
E/log: 发送:3
E/log: 发送:4
E/log: 发送:5
E/log: 发送:6
E/log: 发送:7
E/log: 发送:8
E/log: 发送:9
E/log: 发送:onComplete
E/log: 处理:2
E/log: 处理:3
E/log: 处理:4
E/log: 处理:5
E/log: 处理:6
E/log: 处理:7
E/log: 处理:8
E/log: 处理:9
E/log: 处理:onComplete
背压策略
当事件发出的速度比事件被取走(调用subscription.request(n)方法)的速度快时,没有被及时取走的事件会被缓存起来,但这个缓存空间是有限的——最多能容纳128个事件。那么,当缓存空间已满,又有新的事件发出时该怎么办呢?这就是背压策略所要解决的问题。
(回顾一下Observable-Observer体系:Observable会直接将事件发送给Observer(即无需调用request之类的方法),但如果此时Observer“没空”的话,事件就会被缓存起来,此缓存空间是无限的,直到发生OOM)
/**
* Represents the options for applying backpressure to a source sequence.
*/
public enum BackpressureStrategy {
/**
* OnNext events are written without any buffering or dropping.
* Downstream has to deal with any overflow.
* Useful when one applies one of the custom-parameter onBackpressureXXX operators.
*/
MISSING,
/**
* 缓存已满时再发出新事件就抛出MissingBackpressureException异常。
* Signals a MissingBackpressureException in case the downstream can't keep up.
*/
ERROR,
/**
* 缓存所有事件(即取消对缓存空间大小的限制,可能导致OOM)。
* Buffers all 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
}
测试代码如下:
(日志输出太多了,所以结果就不贴出来了。自己更换不同的背压策略跑跑试试吧,实践出真知!)
Flowable
.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {
for (int i = 1; i < 200; i++) {
Log.e("log", "发送:" + i);
e.onNext(i);
SystemClock.sleep(50);
}
Log.e("log", "发送:onComplete");
e.onComplete();
}
}, BackpressureStrategy.LATEST)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Integer>() {
Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
subscription = s;
subscription.request(1);
}
@Override
public void onNext(Integer integer) {
Log.e("log", "处理:" + integer);
SystemClock.sleep(500);
subscription.request(1);
}
@Override
public void onError(Throwable t) {
Log.e("log", "处理:onError——" + t.toString());
}
@Override
public void onComplete() {
Log.e("log", "处理:onComplete");
}
});
在Android开发中,很少会遇到事件发出速度高于事件处理速度并持续很长时间的情况,因此通常使用Observable和Observer就足够了。