响应式编程
响应式编程(Reactive Programming)是一种编程范式,它专注于数据流和变化传播。在响应式编程中,程序的整体结构是由数据流的变化来驱动的,而不是通过显式的命令式编程指令。主要特点包括:
-
数据流: 在响应式编程中,程序的数据是以流的形式进行传递和处理的。这些数据流可以是同步的也可以是异步的,它们可以是单向的,也可以是双向的。
-
事件驱动: 程序的状态和行为是由事件的发生和响应来驱动的。事件可以是用户输入、网络请求、定时器触发等等。
-
响应式变换: 在数据流中,通过应用各种操作符来对数据进行变换和处理,以产生新的数据流。这些操作符可以是过滤、映射、聚合、合并等等。
-
响应式组合: 可以通过组合多个数据流和操作符来创建更复杂的数据流,以实现更复杂的功能。
-
异步编程: 响应式编程通常与异步编程密切相关,因为数据流可能涉及到异步操作,如异步 I/O、网络请求等。
响应式编程的优势包括:
-
简洁性: 响应式编程使得代码更加简洁、清晰,减少了传统编程中的回调嵌套和临时变量等问题。
-
可读性: 响应式编程使得程序的逻辑更加清晰,代码更易于理解和维护。
-
可组合性: 响应式编程通过数据流的组合和操作符的组合,使得程序更容易扩展和重用。
-
响应性: 响应式编程使得程序能够更快地响应外部事件和用户操作,提高了用户体验。
-
异步性: 响应式编程使得程序能够更好地处理异步操作,提高了系统的并发能力和性能。
总之,响应式编程通过数据流和事件驱动的方式,使得程序更加简洁、清晰、可读、可组合,并且能够更好地处理异步操作,提高了程序的响应性和性能。
为什么要使用 RxJava
- 轻量级框架 < 1M
- 符合响应式编程,着重于数据流和变化的传播,以及对这些变化的响应
- 基于观察者模式,统一了异步任务的回调接口,方便链式调用和操作符扩展
- 通过 Scheduler / Worker 可以方便的进行线程切换
- 在观察者和被观察者之间可以通过操作符完成时间和空间的重组
- 通过操作符可以对事件进行空间重组,使得观察者的逻辑简单而直接,不需要关心数据从何而来,从而使观察者的逻辑较为稳定
- startWith 操作符可以增加网络缓存逻辑
- distinctUntilChanged 操作符可以避免多次刷新UI
- concatWith 可以实现任务链式执行,进教室处理逻辑( fetchToken + enterRoom)
- mergeDelayError 可以合并多个 Observable(进教室逻辑会收集各核心模块初始化的结果,来决定进教室是否成功)
- RecyclerView 需要多次网络请求获取不同类型的数据时,首先通过接口获取要展示的数据类型,然后通过 map 方法返回 Observable 类型的 List(Observable 需要 startWith 一个空的数据集合,主要是配合 combineLatest 使用),进而通过 flatMap 映射为 Observable.combineLatest
- 通过操作符对事件进行时间重组
- debounce 可以实现连续点赞只上报最后的点赞状态
- timeout 可以实现接口超时逻辑
- zipWith 配合 startWith 可以同时拿到点赞状态改变前后的信息,然后只有在点赞状态改变时才上报
- zipWith 配合 skip 可以实现双击判断
- 通过操作符可以对事件进行空间重组,使得观察者的逻辑简单而直接,不需要关心数据从何而来,从而使观察者的逻辑较为稳定
操作符实现思路
- ObservableXXX 的构造方法会把上层 Observable 保存到 source 变量中
- ObservableXXX 的 subscribeActual 一般会生成一个内部的 Observer,用来订阅上层 Observable,并代理 ObservableXXX 的特殊处理逻辑
- 复杂的 ObservableXXX 会同时保存 upstream 和 downstream,用于传递事件并处理 disposable 逻辑,还有一些 ObservableXXX 会通过 DisposableHelper.replace 方法来统一上下游的 Disposable 实例
操作符分类
Creating Observables
create | 自定义发射逻辑 |
just | 发射若干个事件(通过参数个数区分) |
range | 发射连续的数列 |
from | fromArray(发射固定的事件)、fromCallable(每次订阅都会根据supplier获取最新的事件) |
defer | 每次订阅都会获取最新的 Observable |
interval | 固定间隔发送长整型事件(递增) |
timer | 延迟一定时间后发送长整型事件(0L) |
repeat | 重复订阅,在收到 onComplete 事件后会重新订阅 ObservableSource |
Transforming Observables
buffer | 将原始事件整合为固定大小的 List 后发送 |
window | 将原始事件整合到多个不同的 ObservableSource,每个 ObservableSource 依次发送固定数量的原始事件 |
groupby | 将原始事件整合到多个不同的 ObservableSource,每个 ObservableSource 发送不同组的数据 |
flatMap | 将普通事件转换为 ObservableSource 类型的事件,按发射时间整合各 ObservableSource 的发射顺序 |
concatMap | 将普通事件转换为 ObservableSource 类型的事件,顺序整合各 ObservableSource 发射的数据 |
switchMap | 将普通事件转换为 ObservableSource 类型的事件,如果后面的 ObservableSource 开始发射数据,会自动终止前面的 ObservableSource |
map | 数据转换(普通事件 -> 普通事件) |
cast | 类型强制转换,内部通过 map 功能实现类型转换功能 |
scan | 累加所有原始事件,并依次输出对应的结果 |
Filtering
debounce | 收到事件后延时一定时间后向下游发射,延时期间如果收到新的事件,则丢弃原有事件,并重新计时 |
sample | 固定时间采样,如果一段时间间隔内没有新的事件则不发送,否则发送最新的数据 |
distinct | 过滤重复事件(和历史事件比较) |
distinctUntilChanged | 过滤重复事件(和前一个事件比较) |
elementAt | 返回 Maybe 类型 |
filter | 过滤符合条件的事件 |
first | 只发射第一个事件,如果收到 Complete 前没有收到事件,则发射 Default 数据 |
last | 只发射最后一个事件,如果收到 Complete 前没有收到事件,则发射 Default 数据 |
skip / take | 跳过固定数量的事件 / take 固定数量的事件 |
Combining
combineLatest | 在每个数据源都发射了数据的前提下,任何一个数据源发射数据就会触发新的数据发射(新数据根据 combine 方法计算) |
zip | 一对一整合多个数据源发射的数据,遇到一个结束则结束 |
join | 整合两个数据源,每个数据源发射的数据都会对应一个过期时间。其中一个数据源发射数据时,如果另外一个数据源没有未过期的数据,则不发射新的数据 |
merge | 根据发射时间将多个发射源整合为一个,不存在数据转换逻辑,其中一个终止则终止 |
mergeDelayError | 根据发射时间将多个发射源整合为一个,不存在数据转换逻辑,延迟发射 Error 事件 |
switchOnNext | 将发射ObservableSource事件的数据源转换为发射普通数据的数据源,新的数据源会发射当前最新ObservableSource发射的数据 |
ErrorHandling
OnErrorReturn | 遇到错误返回预设的值,然后正常终止 |
OnErrorResumeNext | 遇到 Error 后订阅另外一个 Observable 并发射数据 |
OnExceptionResumeNext | 遇到 Exception 后订阅另外一个 Observable 并发射数据 |
retryWhen | 遇到错误后,会根据参数 Observable 发射数据的时机来重新订阅原始数据源 |
Utility
Delay / DelaySubscription | 延迟发射 / 延迟订阅 |
SubscribeOn / ObserveOn | 切换发射 / 订阅线程 |
TimeInterval | 发射事件序列的时间间隔 |
TimeStamp | 发射事件对应的时间戳信息 |
Timeout | 固定时间未发送事件,则发送 Error 事件 |
doOn(Each、Subscribe、Next、Error、Complete) | |
doOnTerminate | doOnError + doOnComplete |
doOnDispose | |
doFinally | doOnTerminate + doOnDispose |
Conditional and Boolean
all | 判断所有事件是否满足条件,返回 Single |
amb | 抢占式,始终发射第一个开始发射事件的 ObservableSource |
contains / isEmpty | 是否包含/是否为空,对应Single |
DefaultIfEmpty | 如果未发送数据,则发送Default数据 |
SequenceEqual | 一次判断多个数据源发射的数据,如果不相等立即返回false |
SkipUntil / SkipWhile | |
TakeUntil / TakeWhile |
Aggregate
Concat | 按顺序连接多个 Observable |
Count | 计算发射了多少个事件,返回 Single |
Reduce | 和 scan 处理逻辑相同,不过只输出最终结果 |
Collect | 和 reduce 处理逻辑相同,只不过最终输出的是集合类型 |
Scheduler&Worker 接口实现
@Suppress("unused")
fun CoroutineDispatcher.asScheduler(scope: CoroutineScope = GlobalScope)
: Scheduler = CoroutineScheduler(this, scope)
// implement createWorker
internal class CoroutineScheduler(
private val dispatcher: CoroutineDispatcher,
private val scope: CoroutineScope
) : Scheduler() {
override fun createWorker(): Worker = CoroutineWorker(dispatcher, scope)
}
internal class CoroutineWorker(
private val dispatcher: CoroutineDispatcher,
private val scope: CoroutineScope
) : Scheduler.Worker() {
private val supervisorJob = SupervisorJob(scope.coroutineContext[Job])
@Volatile
private var isDisposed = false
override fun isDisposed(): Boolean = isDisposed
override fun dispose() {
if (!isDisposed) {
isDisposed = true
supervisorJob.cancel()
}
}
override fun schedule(run: Runnable, delay: Long, unit: TimeUnit): Disposable {
if (isDisposed || supervisorJob.isCancelled) {
return EmptyDisposable.INSTANCE
}
val decoratedRun = RxJavaPlugins.onSchedule(run)
val job = scope.launch(supervisorJob) {
withContext(dispatcher) {
if (delay > 0L) delay(unit.toMillis(delay))
decoratedRun.run()
}
}
return JobDisposable(job)
}
}
internal class JobDisposable(private val job: Job) : Disposable {
@Volatile
private var isDisposed = false
override fun isDisposed(): Boolean = isDisposed
override fun dispose() {
if (!isDisposed) {
isDisposed = true
job.cancel()
}
}
}
发射器类型
类型 | 描述 |
Observable | 能够发射0或n个数据,并以成功或错误事件终止(onNext、onComplete、onError) |
Flowable | 能够发射0或n个数据,并以成功或错误事件终止;支持Backpressure,可以控制数据源发射的速度(ERROR、BUFFER、DROP、LATEST) |
Single | 只发射单个数据或错误事件(onSuccess、onError) |
Completable | 不发射数据,只处理onComplete和onError事件(onComplete、onError) |
Maybe | 能够发射0或1个数据,要么成功,要么失败((onSuccess、onComplete)互斥关系、onError) |
Subject
Subject 同时实现了 Observer 和 Observable 接口,具体有四个实现类
ReplaySubject
该 Subject 会接收数据,当被订阅时,将所有接收到的数据全部发送给订阅者
BehaviorSubject
当 Observer 订阅了一个 BehaviorSubject,它一开始就会释放 Observable 最近释放的一个数据对象,当还没有任何数据释放时,它则是一个默认值。接下来就会释放 Observable 释放的所有数据。如果 Observable 因异常终止,BehaviorSubject 将不会向后续的 Observer 释放数据,但是会向 Observer 传递一个异常通知
PublishSubject
PublishSubject 仅会向 Observer 释放在订阅之后 Observable 释放的数据
AsyncSubject
AsyncSubject 仅释放 Observable 释放的最后一个数据,并且仅在 Observable 完成之后。然而如果当 Observable 因为异常而终止,AsyncSubject 将不会释放任何数据,但是会向 Observer 传递一个异常通知
FlatMap、ConcatMap、ConcatMapEager区别
- FlatMap 不能保证各个 Observable 发射数据的顺序
- ConcatMap 可以保证各个 Observable 发射数据的顺序,由于是顺序订阅,效率较低
- ConcatMapEager 采用缓存策略,来保证各个 Observable 发射数据的顺序,需要考虑内存占用问题
经典操作符赏析
Observable.subscribeOn
- 该操作符生成并返回 ObservableSubscribeOn 类
- ObservableSubscribeOn 构造方法中保存了 ObservableSource 和 Scheduler
- subscribeActual 方法会创建代理 SubscribeOnObserver:用于向原始 Observer 透传事件,并作为 Disposable 返回给原始 Observer
- SubscribeOnObserver 内部同时处理两个 Disposable:schedule 方法返回的 Disposable(保存在AtomicReference),以及订阅 source 返回的 Disposable(保存在 upstream 中)
- 其中通过执行 scheduler.scheduleDirect 完成线程切换并执行 source.subscribe(parent)
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
public void subscribeActual(final Observer<? super T> observer) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
observer.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
}
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {
final AtomicReference<Disposable> upstream;
SubscribeOnObserver(Observer<? super T> downstream) {
this.downstream = downstream;
this.upstream = new AtomicReference<Disposable>();
}
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.setOnce(this.upstream, d);
}
@Override
public void onNext(T t) {
downstream.onNext(t);
}
@Override
public void dispose() {
DisposableHelper.dispose(upstream);
DisposableHelper.dispose(this);
}
}
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
source.subscribe(parent);
}
}
Observable.observeOn
- 该操作符生成并返回ObservableObserverOn类
- ObservableSubscribeOn构造方法中保存了ObservableSource和Scheduler
- subscribeActual方法会创建代理Observer(ObserveOnObserver):内部在onNext、onError、onComplete方法中会把事件存储在queue中,并调用worker的schedule方法,run方法中会循环读取queue中的任务发送给下一层的Observer,并处理delayError相关逻辑
public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {
public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
super(source);
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T> implements Observer<T>, Runnable {
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
@Override
public void run() {
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
}
Observable.map
- 该操作符生成并返回ObservableMap类
- ObservableMap构造方法中保存了ObservableSource和function
- subscribeActual方法会创建代理Observer(MapObserver),内部onNext、onComplete、onError方法会直接执行map-function,然后也不会切换线程
public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
final Function<? super T, ? extends U> function;
public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
super(source);
this.function = function;
}
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new MapObserver<T, U>(t, function));
}
}
Observable.flatMap
- 该操作符生成并返回ObservableFlatMap类
- subscribeActual方法会创建MergeObserver(在MergeObserver构造方法中保存原始订阅者),观察数据源,并保存Disposable到upstream
- MergeObserver#onNext方法中调用mapper.apply,创建InnerObserver观察新的数据源
- InnerObserver#onNext方法调用parent(MergeObserver)#tryEmit方法将订阅数据返回给MergeObserver,并最终发送给原始订阅者
- 用户通过调用MergeObserver来dispose掉整个链路(upstream、innerObserver数组)
public final class ObservableFlatMap<T, U> extends AbstractObservableWithUpstream<T, U> {
final Function<? super T, ? extends ObservableSource<? extends U>> mapper;
final boolean delayErrors;
final int maxConcurrency;
final int bufferSize;
public ObservableFlatMap(ObservableSource<T> source,
Function<? super T, ? extends ObservableSource<? extends U>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
super(source);
this.mapper = mapper;
this.delayErrors = delayErrors;
this.maxConcurrency = maxConcurrency;
this.bufferSize = bufferSize;
}
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new MergeObserver<T, U>(t, mapper, delayErrors, maxConcurrency, bufferSize));
}
static final class MergeObserver<T, U> extends AtomicInteger implements Disposable, Observer<T>
MergeObserver(Observer<? super U> actual,
Function<? super T, ? extends ObservableSource<? extends U>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
this.downstream = actual;
this.mapper = mapper;
this.delayErrors = delayErrors;
this.maxConcurrency = maxConcurrency;
this.bufferSize = bufferSize;
if (maxConcurrency != Integer.MAX_VALUE) {
sources = new ArrayDeque<ObservableSource<? extends U>>(maxConcurrency);
}
this.observers = new AtomicReference<InnerObserver<?, ?>[]>(EMPTY);
}
// 给真正的订阅者返回的Disposable为MergeObserver,在MergeObserver中保存上层订阅的Disposable到upstream
@Override
public void onSubscribe(Disposable d) {
if (DisposableHelper.validate(this.upstream, d)) {
this.upstream = d;
downstream.onSubscribe(this);
}
}
// 每次onNext都会通过mapper来订阅新的数据源
@Override
public void onNext(T t) {
ObservableSource<? extends U> p = mapper.apply(t)
InnerObserver<T, U> inner = new InnerObserver<T, U>(this, uniqueId++);
if (addInner(inner)) {
p.subscribe(inner);
}
}
// 保存InnerObserver,用于Dispose
boolean addInner(InnerObserver<T, U> inner) {
for (;;) {
InnerObserver<?, ?>[] a = observers.get();
int n = a.length;
InnerObserver<?, ?>[] b = new InnerObserver[n + 1];
System.arraycopy(a, 0, b, 0, n);
b[n] = inner;
if (observers.compareAndSet(a, b)) {
return true;
}
}
}
boolean disposeAll() {
upstream.dispose();
InnerObserver<?, ?>[] a = observers.get();
if (a != CANCELLED) {
a = observers.getAndSet(CANCELLED);
if (a != CANCELLED) {
for (InnerObserver<?, ?> inner : a) {
inner.dispose();
}
return true;
}
}
return false;
}
}
static final class InnerObserver<T, U>
extends AtomicReference<Disposable> implements Observer<U> {
@Override
public void onNext(U t) {
if (fusionMode == QueueDisposable.NONE) {
parent.tryEmit(t, this);
} else {
parent.drain();
}
}
@Override
public void onError(Throwable t) {
if (parent.errors.addThrowable(t)) {
if (!parent.delayErrors) {
parent.disposeAll();
}
done = true;
parent.drain();
} else {
RxJavaPlugins.onError(t);
}
}
}
}
FlatMap Demo
// 常规flatmap
fun handleFlatMap() {
Observable.create<Int> {
Log.i("ebb1", Thread.currentThread().name)
it.onNext(1)
it.onNext(2)
it.onComplete()
}
.flatMap {
Observable.create<Float> { emitter ->
Log.i("ebb2", Thread.currentThread().name)
emitter.onNext(3.14f)
emitter.onComplete()
}.subscribeOn(Schedulers.io())
}
.map {
Log.i("ebb3", Thread.currentThread().name)
it
}
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.map {
Log.i("ebb4", Thread.currentThread().name + " " + it)
}
.subscribe()
}
//2021-06-22 15:21:12.434 I/ebb1: RxCachedThreadScheduler-1
//2021-06-22 15:21:12.439 I/ebb2: RxCachedThreadScheduler-3
//2021-06-22 15:21:12.439 I/ebb3: RxCachedThreadScheduler-3
//2021-06-22 15:21:12.440 I/ebb2: RxCachedThreadScheduler-2
//2021-06-22 15:21:12.440 I/ebb3: RxCachedThreadScheduler-2
//2021-06-22 15:21:12.502 I/ebb4: main 3.14
//2021-06-22 15:21:12.503 I/ebb4: main 3.14
//带异常的flatmap操作
//由于ObservableObserveOn向原始订阅者发送数据时会暂存到queue中,
//并通过Worker.schedule切换到线程,而且设置状态也是不切换线程的,
//这会有一定概率导致onNext状态丢失,如果不调用sleep,则订阅者基本不会收到onNext事件
fun handleFlatMap() {
Observable.create<Int> {
Log.i("ebb1", Thread.currentThread().name)
it.onNext(1)
it.onNext(2)
it.onComplete()
}
.flatMap {
Observable.create<Float> { emitter ->
Log.i("ebb2", Thread.currentThread().name)
emitter.onNext(3.14f)
Thread.sleep(1000)
emitter.onError(Exception("error"))
}
// .subscribeOn(Schedulers.io())
// 这里需要屏蔽flatmap内的线程切换,否则会有一定概率提示错误无法分发,具体原因没有细追
}
.map {
Log.i("ebb3", Thread.currentThread().name)
it
}
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.map {
Log.i("ebb4", Thread.currentThread().name + " " + it)
it
}
.subscribe({
Log.e("ebb5", "$it")
},{
Log.e("ebb5", it.message)
})
}
Observable.retryWhen
- 该操作符生成并返回ObservableRetryWhen类
- 构造方法中保存了Source和Handler
- subscribeActual方法中创建了一个PublishSubject,通过该Subject来对外通知错误信息,内部通过parent.inner来观察外部注入的Observable,并再次调用RepeatWhenObserver的subscribeNext方法
public final class ObservableRetryWhen<T> extends AbstractObservableWithUpstream<T, T> {
final Function<? super Observable<Throwable>, ? extends ObservableSource<?>> handler;
public ObservableRetryWhen(ObservableSource<T> source,
Function<? super Observable<Throwable>, ? extends ObservableSource<?>> handler) {
super(source);
this.handler = handler;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
Subject<Throwable> signaller = PublishSubject.<Throwable>create().toSerialized();
ObservableSource<?> other = handler.apply(signaller)
RepeatWhenObserver<T> parent = new RepeatWhenObserver<T>(observer, signaller, source);
observer.onSubscribe(parent);
other.subscribe(parent.inner);
parent.subscribeNext();
}
static final class RepeatWhenObserver<T> extends AtomicInteger implements Observer<T>, Disposable {
void subscribeNext() {
if (wip.getAndIncrement() == 0) {
do {
if (isDisposed()) {
return;
}
if (!active) {
active = true;
source.subscribe(this);
}
} while (wip.decrementAndGet() != 0);
}
}
@Override
public void onError(Throwable e) {
DisposableHelper.replace(upstream, null);
active = false;
signaller.onNext(e);
}
final class InnerRepeatObserver extends AtomicReference<Disposable> implements Observer<Object> {
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.setOnce(this, d);
}
@Override
public void onNext(Object t) {
innerNext();
}
@Override
public void onError(Throwable e) {
innerError(e);
}
@Override
public void onComplete() {
innerComplete();
}
}
}
}
observeOn 作用于该操作符之后的操作符直到出现新的 observeOn 操作符
subscribeOn 作用于该操作符之前的 Observable 的创建操符作以及 doOnSubscribe 操作符 ,换句话说就是 doOnSubscribe 以及 Observable 的创建操作符总是被其之后最近的 subscribeOn 控制