ReactiveX: An API for asynchronous programming with observable streams.
ReactiveX(Reactive Extensions),一般简写为Rx,是一个使用可观察数据流进行异步编程的编程接口。由微软的架构师Erik Meijer领导的团队开发,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便地编写异步和基于事件的程序,现在已经有了RxJava、RxJS、Rx.NET、RxScala、RxClojure、RxSwift等基本所有主流语言的实现,受到越来越多的开发者的欢迎,开源社区也普遍在使用。
ReactiveX不仅仅是一个API,它是一种思想、一种编程突破,它影响了许多其它的API、框架甚至编程语言。
无论你开发app还是后台应用,你总会时不时地编写一些异步或基于事件的代码,但你会发现很难完美地处理工作线程和主线程的切换、异常的处理、线程的取消、线程同步等等问题,而且在多个线程协调处理业务逻辑时代码结构变得异常的复杂而且还容易出错。
使用Rx,你可以:
也就是说,ReactiveX的Observable模型让你对异步事件流的处理就像平时对数据集(如数组)进行简单、可组合的处理一样,让你从混乱的回调中解脱出来,写出更高可读性、更不容易产生Bug的代码。
Rx结合了观察者模式、迭代器模式和函数式编程的优秀思想。Rx扩展观察者模式以支持数据/事件序列,添加了一些操作符以使你可以声明式的组合这些序列,而无需关注底层的实现:如线程、同步、线程安全、并发数据结构和非阻塞IO 。
Future.get()
,这样的话异步执行的优势就完全没有了。或许你会考虑使用回调来解决
Future.get()
过早阻塞的问题,但是对于嵌套的异步任务来说,使用回调同样会使代码变得混乱,如 benjchristensen/CallbackB.java。Rx的Observable从另一方面讲就是为了组合异步数据流准备的,使用RX你可以非常方便地组合多个Observable。
T next()
方法获取数据,Observable通过
onNext(T)
发射数据;Iterable遇到错误会抛出异常(throws Exception),Observable遇到错误会调用
onError(Exception)
方法;Iterable可以利用
!hasNext()
方法判断是否完成,Observable通过调用
onCompleted()
方法表示完成。
RxJava是JVM上的ReactiveX实现 – 一个在 Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。
RxJava目前版本是2.1.0,2.x版本相对于1.x版本有了很大的改动,甚至可以说是重写,而1.x版本截止到2017年6月1号不会增加新的操作符,仅仅修复Bug,截止到2018年3月31号完全停止开发维护。所以1.x版本的RxJava就不再关注了。
RxAndroid是Android上的ReactiveX实现–Android上的RxJava bindings。
RxAndroid添加尽可能少的类到RxJava以确保在Android应用中写响应式组件能够简单省事,尤其是它提供的调度器可以很好地调度主线程和任意Lopper线程。
信号(Signal): 作名词时表示onSubscribe
, onNext
, onComplete
, onError
, request(n)
或cancel
方法的触发信号,作动词时表示触发一个信号。
请求(Demand): 作名词时表示由Publisher尚未交付(履行)的Subscriber请求的元素的总数。作动词时表示请求更多的元素的行为。
同步(Synchronous): 在调用线程中执行。
正常返回(Return normally): 永远只向调用者返回一个声明类型的值, 向Subscriber
发失败信号的唯一合法方法是通过onError
方法。
背压(Backpressure): Observable发送消息太快以至于它的操作符或者订阅者不能及时处理相关的消息的场景。
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
/**
* 一个可能无限数量的序列元素的提供者,根据从其Subscriber收到的请求发送它们。
* `Publisher`可以在不同的时间点动态地服务多个通过`subscribe(Subscriber)`方法订阅的Subscriber。
*
* @param 信号元素类型.
*/
public interface Publisher<T> {
/**
* 请求Publisher开始数据流.
* 这是一个可以被多次调用的"工厂方法", 但每次都会开始一个新的Subscription.
* 每个Subscription将只会为一个Subscriber工作.
* 一个Subscriber应该只能向一个Publisher订阅一次.
* 如果Publisher拒绝了订阅尝试或者订阅失败了,它将通过Subscriber#onError发error信号
*
* @param s 将消费来自Publisher的信号的Subscriber
*/
public void subscribe(Subscriber super T> s);
}
调用Publisher.subscribe(Subscriber)
后Subscriber
的响应可能是的这样的方法调用序列:
onSubscribe onNext* (onError | onComplete)?
也就是说,如果Subscription没被cancel的话,onSubscribe
信号将总会被触发,之后根据Subscriber的请求可能有多个onNext
信号,之后如果出错的话会有一个onError
信号,如果没有元素的话会有一个onComplete
信号。
ReactiveX中最重要的概念就是流(stream),任何东西都可以看作是流,最常见的就是网络数据流、UI事件流,产生stream的通常叫作被观察者(Observable)/生产者,而监听、处理stream的通常叫做观察者(Observer)/消费者,两者的关联通常叫作订阅(Subscribe)。
上面说的Publisher
就是产生事件的事件源,而RxJava根据不同使用情况提供了几个事件源的类,其中Flowable
就是Publisher
的实现类:
io.reactivex.Flowable
: 0..N个流,支持Reactive-Streams和背压(backpressure)io.reactivex.Observable
: 0..N个流,不支持背压(backpressure)io.reactivex.Single
: 一个只包含一个item或error的流io.reactivex.Completable
: 一个不包含任何item只包含completion或error信号的流io.reactivex.Maybe
: 一个只包含一个maybe value或者error的流首先来看一下Flowable
:
import io.reactivex.functions.Consumer;
Flowable.just("Hello world")
.subscribe(new Consumer() {
@Override public void accept(String s) {
System.out.println(s);
}
});
Flowable
是为了更好地处理背压问题而新设计的类以弥补Observable
的不足,也就是说,Observable
不支持背压处理,一旦未及时处理的事件数累积到一定程度就会产生MissingBackpressureException
或者OutOfMemoryError
。
如果发射事件的Observable(上游)和接收处理事件的Observer(下游)工作在不同线程,就可能会出现发射事件的速度与处理事件的速度不一样的情况,如果发射的太快,就会出现事件积累的情况,而事件的积累会导致大量的资源浪费甚至OOM。而解决这一情况最直接暴力的方式就是控制上游的发射数量或发射速度,以给下游足够的事件处理事件,但是控制发射数量可能会导致部分事件被丢弃,控制发射速度可能影响性能。所以Flowable
采用了更优雅的方式来解决这一问题,下游可以把自己“处理事件的能力”告诉上游,上游根据这个来决定要不要继续发射事件,也就是说下游可以根据自身情况主动通知上游发送事件,这也就完美解决了上下游流速不均衡的问题。
Flowable
提供了工厂方法create(FlowableOnSubscribe
,可以通过第二个参数指定背压策略,MISSING
表明由下游处理事件溢出问题,一般用于自定义参数的onBackpressureXXX
操作符场景,ERROR
表明如果下游跟不上上游的流速就抛出MissingBackpressureException
,BUFFER
表明缓冲所有的onNext值直到下游消费,DROP
表明如果下游跟不上就丢弃最近的onNext值,LATEST
表明如果下游跟不上就只保留最近的onNext值,覆盖之前的值。Flowable
默认的bufferSize是128,由系统参数rx2.buffer-size
决定。
Observable
可以看作是Flowable
的阉割版,只是不支持背压逻辑,其它的逻辑、方法与Flowable
是基本一样的。Observable
是ObservableSource
接口的实现,而ObservableSource
表示一个基本的、不支持背压的Observable源,由Observer
消费,ObservableSource
只有一个方法void subscribe(Observer super T> observer)
用来订阅给定的Observer
。也就是说Subscriber
订阅Flowable
,Observer
订阅Observable
。
Observable
可以通过非常多的工厂方法和操作符构建,如通过just()
操作符构建:
Observable.just("one", "two", "three", "four", "five")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver() {
@Override
public void onNext(String value) {
Log.d(TAG, "onNext(" + value + ")");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError()", e);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete()");
}
});
那什么时候使用Observable
,什么时候使用Flowable
呢?
何时使用Observable
:
何时使用Flowable
:
ResultSet.next()
来控制。Single
与Observable
类似但只能发射一个onSuccess
或onError
给它的消费者io.reactivex.SingleObserver
:
public interface SingleObserver<T> {
void onSubscribe(Disposable d);
void onSuccess(T value);
void onError(Throwable e);
}
响应流的事件模式为:onSubscribe (onSuccess | onError)?
Completable
用来表示一个延迟计算且不关心任何数据只关心完成和异常,只能发射一个onComplete
或onError
给它的消费者o.reactivex.CompletableObserver
:
public interface CompletableObserver {
void onSubscribe(Disposable d);
void onComplete();
void onError(Throwable e);
}
响应流的事件模式为:onSubscribe (onComplete | onError)?
Maybe
从概念上讲是Single
和Completable
的结合,提供了一种捕获一些响应源发射0或1个item或一个error的发射模式的手段,用来表示一个延迟计算。Maybe
以MaybeSource
作为基本接口,以MaybeObserver
作为信号接收接口。由于最多只能发射一个元素Maybe
就没打算支持背压处理,这就意味着,在onSubscribe(Disposable)
被调用后可能接着调用一个其它onXXX
方法,与Flowable
不同的是,如果只有一个值信号,只有onSuccess
被调用而不是onComplete
,使用这种新的基本响应类型与其他类型几乎是一样的,因为它提供了一个适用于0或1个item序列的Flowable
操作符子集。
Maybe.just(1)
.map(v -> v + 1)
.filter(v -> v == 1)
.defaultIfEmpty(2)
.test()
.assertResult(2);
响应流的事件模式为:onSubscribe (onSuccess | onError | onComplete)?
/**
* 将Subscriber的一个实例传给Publisher#subscribe(Subscriber)方法后,将会收到一次onSubscribe(Subscription)方法调用
* 在Subscription#request(long)被调用之前不会受到进一步通知
* 在发送请求信号后:
* 调用一到多次onNext(Object)方法,最多调用Subscription#request(long)中定义的次数
* 调用一次onError(Throwable)或onComplete()方法表明终止状态,之后不会发送进一步事件
* 只要Subscriber实例还能够处理,就可以通过Subscription#request(long)发请求信号
*
* @param 信号元素类型
*/
public interface Subscriber<T> {
/**
* 在调用Publisher#subscribe(Subscriber)之后调用
* 直到Subscription#request(long)被调用才开始数据流
* 每当需要更多数据时,这个Subscriber实例都有责任调用Subscription#request(long)
* Publisher只有在Subscription#request(long)被调用后才会发送通知
*
* @param s 可以通过Subscription#request(long)方法请求数据的Subscription
*/
public void onSubscribe(Subscription s);
/**
* Publisher发送的数据通知,以响应Subscription#request(long)的请求
*
* @param t the element signaled
*/
public void onNext(T t);
/**
* 失败的结束状态
* 即使再次调用Subscription#request(long)也不会再发送进一步事件
*
* @param t the throwable signaled
*/
public void onError(Throwable t);
/**
* 成功的结束状态
* 即使再次调用Subscription#request(long)也不会再发送进一步事件
*/
public void onComplete();
}
为了在构建stream消费者时有更少的内部状态,Rxjava2为Flowable
(和Observable
)分别定义了DefaultSubscriber
,ResourceSubscriber
和DisposableSubscriber
(以及他们的XObserver
变体),以提供资源跟踪支持,可以在外部通过dispose()
方法cancelled(取消)或disposed(丢弃):
ResourceSubscriber subscriber = new ResourceSubscriber() {
@Override
public void onStart() {
request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer t) {
System.out.println(t);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Done");
}
};
Flowable.range(1, 10).delay(1, TimeUnit.SECONDS).subscribe(subscriber);
subscriber.dispose();
为了能更好的控制订阅关系,每个基本响应类都提供了E subscribeWith(E subscriber)
方法以返回订阅的subscriber/observer:
CompositeDisposable composite2 = new CompositeDisposable();
composite2.add(Flowable.range(1, 5).subscribeWith(subscriber));
在管理请求时有一点需要注意,在Subscriber.onSubscribe
或ResourceSubscriber.onStart
方法中调用request(n)
可能会马上触发onNext
方法(在onSubscribe/onStart
方法返回前):
Flowable.range(1, 3).subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
System.out.println("OnSubscribe start");
s.request(Long.MAX_VALUE);
System.out.println("OnSubscribe end");
}
@Override
public void onNext(Integer v) {
System.out.println(v);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Done");
}
});
将会打印:
OnSubscribe start
1
2
3
Done
OnSubscribe end
也就是说,如果在onSubscribe/onStart
方法中调用request
之后再做一些初始化工作,那么onNext
方法可能就看不到初始化的影响。为了避免出现这种情况,要确保onSubscribe/onStart
中完成所有的初始化工作再调用request
方法。
/**
* Subscription表示Subscriber订阅Publisher的一对一生命周期
* 它只能由一个Subscriber使用一次
* 它用于数据请求和取消请求(允许资源清理)
*
*/
public interface Subscription {
/**
* Publisher将不会发送任何事件直到通过该方法发送请求信号
* 可以随时、频繁地调用,但未完成积累的请求决不能超过Long.MAX_VALUE
* 未完成积累的请求数为Long.MAX_VALUE可能会被Publisher视为"有效无限"
* Publisher可以发送的任何请求的信息,只有信号请求可以被安全处理
* 如果流结束了Publisher发送数量可以少于请求的数量,但是随后必须发射Subscriber#onError(Throwable)或Subscriber#onComplete()
*
* @param n 向上游Publisher请求的元素数量(严格正数)
*/
public void request(long n);
/**
* 请求Publisher停止发射数据并且清理资源
* 由于这个请求是异步的,在调用cancel方法后,数据可能仍然被发送以满足之前的信号请求
*/
public void cancel();
}
在Android中,对异步任务生命周期的管理尤为重要,而RxJava提供的最重要的接口就是Disposable
:
public interface Disposable {
void dispose();
boolean isDisposed();
}
由于ResourceSubscriber
和DisposableSubscriber
(以及他们的XObserver
变体)都实现了Disposable
接口,对于单个资源请求我们可以直接调用它的dispose()
方法丢弃,对于多个请求,我们就要借助CompositeDisposable
来管理了,CompositeDisposable
是多个Disposable
的容器,提供了复杂度为O(1)的添加删除操作:
public class MainActivity extends Activity {
private static final String TAG = "RxAndroidSamples";
private final CompositeDisposable disposables = new CompositeDisposable();
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
findViewById(R.id.button_run_scheduler).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
onRunSchedulerExampleButtonClicked();
}
});
}
@Override protected void onDestroy() {
super.onDestroy();
disposables.clear();
}
void onRunSchedulerExampleButtonClicked() {
disposables.add(sampleObservable()
// Run on a background thread
.subscribeOn(Schedulers.io())
// Be notified on the main thread
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver() {
@Override public void onComplete() {
Log.d(TAG, "onComplete()");
}
@Override public void onError(Throwable e) {
Log.e(TAG, "onError()", e);
}
@Override public void onNext(String string) {
Log.d(TAG, "onNext(" + string + ")");
}
}));
}
static Observable sampleObservable() {
return Observable.defer(new Callable>() {
@Override public ObservableSource extends String> call() throws Exception {
// Do some long running operation
SystemClock.sleep(5000);
return Observable.just("one", "two", "three", "four", "five");
}
});
}
}
注意,CompositeDisposable
的clear()
方法和dispose()
方法类似,clear()
可以多次被调用来丢弃容器中所有的Disposable
,但dispose()
被调用一次后就会失效。
对于订阅生命周期的封装库最常见的是trello/RxLifecycle,不过它需要LifecycleProvider
才能工作,大部分情况下你只能选择继承它的RxActivity
或RxFragment
。另一个很有意思的封装是zhihu/RxLifecycle,它利用TakeUtil
操作符和一个HeadlessFragment
来控制Observable的生命周期。
/**
* Processor表示一个处理过程—Subscriber和Publisher都必须遵守两者的契约
*
* @param Subscriber的信号元素类型
* @param Publisher的信号元素类型
*/
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
References