專案經驗,如需轉載,請註明作者:Yuloran (t.cn/EGU6c76)
前言
本文簡析 RxJava2
的 subscribeOn
和 zip
操作符。
術語解釋
Single.just().map().flatMap().subscribeOn().observeOn().subscribe();
複製程式碼
上述程式碼中,Single
到 subscribe()
之間的都稱為 操作符
,想像一下自己就是其中一個 操作符
,那麼位於左邊的便稱為 上游
,位於右邊的則稱為 下游
,故上下游其實是相對的。
原始碼分析指南
由於 RxJava
是鏈式呼叫,鏈條長度沒有限制,所以原始碼分析需要技巧,直接從頭看到尾,容易看的頭暈。所以建議先寫一個『最短的呼叫鏈』去分析,然後舉一反三,推測其設計思想(仔細想想就知道,那麼多操作符,肯定不需要每個都去分析,也不現實,所以只要理解其設計思想就行了)。
首先,我們需要明確每一次操作符呼叫的返回型別是什麼:subscribe()
左邊都是觀察者的上游,而觀察者的上游肯定是被觀察者。所以每一次操作符呼叫的返回型別都是被觀察者(而且每次都返回一個新的被觀察者,內部持有對上一個觀察者的引用)。鑑於 RxJava
的被觀察者型別較多,有:
io.reactivex.Flowable
: 0..N flows, supporting Reactive-Streams and backpressureio.reactivex.Observable
: 0..N flows, no backpressure,io.reactivex.Single
: a flow of exactly 1 item or an error,io.reactivex.Completable
: a flow without items but only a completion or error signal,io.reactivex.Maybe
: a flow with no items, exactly one item or an error.
背壓:上游資料發射太快,下游來不及處理,導致緩衝區溢位(類比我國人民都知道的水缸進水、放水問題)
本文僅以 io.reactivex.Single
為例進行分析,其他型別舉一反三即可,此處先給出物件引用關係圖,根據此圖即可推出函式呼叫軌跡:
原始碼分析都寫在註釋裡了,subscribeOn
操作符是對 java 併發框架和 Android Handler 的封裝,zip
操作符則是利用 java 原子類實現的。
解析 subscribeOn
demo
// Case2: 在非UI執行緒執行並關注結果
Single.fromCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return generateRandom();
}
}).subscribeOn(Schedulers.io()).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Logger.d(TAG, "test: accept(Integer integer) invoked on %s", Thread.currentThread().getName());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Logger.d(TAG, "test: accept(Throwable throwable) invoked on %s", Thread.currentThread().getName());
}
});
複製程式碼
fromCallable(Callable callable) [-> Single.java]
public static <T> Single<T> fromCallable(final Callable<? extends T> callable) {
ObjectHelper.requireNonNull(callable, "callable is null");
// RxJavaPlugins 裡是全域性鉤子函式,分析原始碼時無視即可,此處就是返回 SingleFromCallable
return RxJavaPlugins.onAssembly(new SingleFromCallable<T>(callable));
}
複製程式碼
RxJavaPlugins
裡是全域性鉤子函式,無需關注
SingleFromCallable [-> SingleFromCallable.java]
// 注意繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleFromCallable<T> extends Single<T> {
// 回撥函式
final Callable<? extends T> callable;
public SingleFromCallable(Callable<? extends T> callable) {
// 儲存為全域性變數
this.callable = callable;
}
@Override
protected void subscribeActual(SingleObserver<? super T> observer) {
// 一個 run() 方法體為空的 RunnableDisposable 物件,用來取消訂閱
Disposable d = Disposables.empty();
// 呼叫下游(本示例此處為SubscribeOnObserver)的 onSubscribe()
observer.onSubscribe(d);
// 已取消訂閱的,直接返回,不會發射任何值
if (d.isDisposed()) {
return;
}
T value;
try {
// 呼叫 callable.call() 獲取值
value = ObjectHelper.requireNonNull(callable.call(), "The callable returned a null value");
} catch (Throwable ex) {
// 捕獲所有異常,所以使用 rxjava 時,自己寫的方法收不到異常通知,需訂閱一個 Consumer<Throwable>
Exceptions.throwIfFatal(ex);
if (!d.isDisposed()) {
// 發射一個 error 事件給下游
observer.onError(ex);
} else {
RxJavaPlugins.onError(ex);
}
return;
}
if (!d.isDisposed()) {
// 發射一個 success 事件給下游
observer.onSuccess(value);
}
}
}
複製程式碼
subscribeOn(Scheduler scheduler) [-> Single.java]
public final Single<T> subscribeOn(final Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
// 返回 SingleSubscribeOn
return RxJavaPlugins.onAssembly(new SingleSubscribeOn<T>(this, scheduler));
}
複製程式碼
SingleSubscribeOn [-> SingleSubscribeOn.java]
// 注意繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleSubscribeOn<T> extends Single<T> {
// 上游
final SingleSource<? extends T> source;
// 執行緒排程器
final Scheduler scheduler;
public SingleSubscribeOn(SingleSource<? extends T> source, Scheduler scheduler) {
// 儲存上游為 this.source
this.source = source;
// 儲存執行緒排程器為 this.scheduler
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver<? super T> s) {
// 將下游和上游包裝為 SubscribeOnObserver
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s, source);
// 呼叫下游的 onSubscribe(),此時還沒有切換執行緒,所以 onSubscribe() 是在原執行緒執行的
s.onSubscribe(parent);
// 將 SubscribeOnObserver 扔到執行緒排程器中執行,此處就是 IoScheduler,內部實現基於 jdk 的 ExecutorService、FutureTask 和 Future
Disposable f = scheduler.scheduleDirect(parent);
// 將排程器返回的 Disposable(一個實現了 Disposable 和 Runnable 介面的 DisposeTask) 物件設定給 SubscribeOnObserver 的 task,用來取消訂閱、中斷執行緒執行
parent.task.replace(f);
}
// 繼承自 AtomicReference,實現了 SingleObserver、Disposable、Runnable介面
// SingleObserver:當作下游
// Disposable:傳給下游以便下游用來取消訂閱
// Runnable:用來提交給 ExecutorService
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, Runnable {
private static final long serialVersionUID = 7000911171163930287L;
// 下游
final SingleObserver<? super T> actual;
// 用來取消訂閱、中斷執行緒執行
final SequentialDisposable task;
// 上游
final SingleSource<? extends T> source;
SubscribeOnObserver(SingleObserver<? super T> actual, SingleSource<? extends T> source) {
// 將下游儲存為 this.actual
this.actual = actual;
// 將上游儲存為 this.source
this.source = source;
// 一個繼承自 AtomicReference 實現了 Disposable 介面的物件,用來取消訂閱、中斷執行緒執行
this.task = new SequentialDisposable();
}
@Override
public void onSubscribe(Disposable d) {
// 因為繼承自 AtomicRefrence,此處將取消訂閱的控制程式碼(本示例中此處為 Disposables.empty())設定給內部的物件引用,用於取消對上游的訂閱
DisposableHelper.setOnce(this, d);
}
@Override
public void onSuccess(T value) {
// 上游呼叫 observer.onSuccess() 時,會呼叫到這裡,此處繼續呼叫下游的 onSuccess() 將值向下傳遞
actual.onSuccess(value);
}
@Override
public void onError(Throwable e) {
// 上游呼叫 observer.onError() 時,會呼叫到這裡,此處繼續呼叫下游的 onError() 將錯誤向下傳遞
actual.onError(e);
}
@Override
public void dispose() {
// 取消對上游的訂閱
DisposableHelper.dispose(this);
// 中斷執行緒執行
task.dispose();
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
@Override
public void run() {
// 線上程池中執行 source.subscribe(),本示例會觸發:
// SingleFromCallable.subscribe()->
// SingleFromCallable.suscribeActual()->
// this.onSuccess(callable.call())
source.subscribe(this);
}
}
}
複製程式碼
subscribe() [-> Single.java]
public final Disposable subscribe(final Consumer<? super T> onSuccess, final Consumer<? super Throwable> onError) {
ObjectHelper.requireNonNull(onSuccess, "onSuccess is null");
ObjectHelper.requireNonNull(onError, "onError is null");
// 將 successConsumer、throwableConsumer 包裝成 ConsumerSingleObserver,作為觀察者
ConsumerSingleObserver<T> s = new ConsumerSingleObserver<T>(onSuccess, onError);
// 呼叫 subscribe(SingleObserver subscriber)
subscribe(s);
// ConsumerSingleObserver 實現了 Disposable 介面,持有它,可以用來取消訂閱
return s;
}
複製程式碼
subscribe(SingleObserver subscriber) [-> Single.java]
public final void subscribe(SingleObserver<? super T> subscriber) {
ObjectHelper.requireNonNull(subscriber, "subscriber is null");
subscriber = RxJavaPlugins.onSubscribe(this, subscriber);
ObjectHelper.requireNonNull(subscriber, "subscriber returned by the RxJavaPlugins hook is null");
try {
// 繼續呼叫抽象方法 subscribeActual(SingleObserver subscriber),即呼叫子類的 subscribeActual(SingleObserver subscriber)
// 本示例中,此處子類為 SingleSubscribeOn,原始碼分析見上方
subscribeActual(subscriber);
} catch (NullPointerException ex) {
throw ex;
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
NullPointerException npe = new NullPointerException("subscribeActual failed");
npe.initCause(ex);
throw npe;
}
}
複製程式碼
ConsumerSingleObserver [->ConsumerSingleObserver .java]
public final class ConsumerSingleObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, LambdaConsumerIntrospection {
private static final long serialVersionUID = -7012088219455310787L;
// successConsumer
final Consumer<? super T> onSuccess;
// throwableConsumer
final Consumer<? super Throwable> onError;
public ConsumerSingleObserver(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError) {
// 將 successConsumer 儲存為全域性變數 this.onSuccess
this.onSuccess = onSuccess;
// 將 throwableConsumer 儲存為全域性變數 this.onError
this.onError = onError;
}
@Override
public void onError(Throwable e) {、
// 最後設定為已取消訂閱
lazySet(DisposableHelper.DISPOSED);
try {
// 回撥 throwableConsumer
onError.accept(e);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
RxJavaPlugins.onError(new CompositeException(e, ex));
}
}
@Override
public void onSubscribe(Disposable d) {
// 本示例中,d 為 SubscribeOnObserver
DisposableHelper.setOnce(this, d);
}
@Override
public void onSuccess(T value) {
// 最後設定為已取消訂閱
lazySet(DisposableHelper.DISPOSED);
try {
// 回撥 successConsumer
onSuccess.accept(value);
} catch (Throwable ex) {
// 異常被 rxjava 捕獲,所以自己寫的 successConsumer 收不到異常
Exceptions.throwIfFatal(ex);
RxJavaPlugins.onError(ex);
}
}
@Override
public void dispose() {
// 取消訂閱
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return get() == DisposableHelper.DISPOSED;
}
@Override
public boolean hasCustomOnError() {
return onError != Functions.ON_ERROR_MISSING;
}
}
複製程式碼
時序圖
解析 zip
demo
// Case6: 併發讀取不同資料來源,轉換成同型別後,合併
Single<IBook> novel = Single.fromCallable(new Callable<Novel>() {
@Override
public Novel call() throws Exception {
return getNovel();
}
}).map(new Function<Novel, IBook>() {
@Override
public IBook apply(Novel novel) throws Exception {
return new NovelAdapter(novel);
}
}).subscribeOn(Schedulers.io());
Single<IBook> rxJava2Tutorial = Single.fromCallable(new Callable<RxJava2Tutorial>() {
@Override
public RxJava2Tutorial call() throws Exception {
return getRxJava2Tutorial();
}
}).map(new Function<RxJava2Tutorial, IBook>() {
@Override
public IBook apply(RxJava2Tutorial rxJava2Tutorial) throws Exception {
return new RxJava2TutorialAdapter(rxJava2Tutorial);
}
}).subscribeOn(Schedulers.io());
// 注意此處呼叫的是合併兩個 SingleSource 的方法,zip 操作符的過載方法很多,從 2~9 都有,相應的變換函式也有從 2~9,無語啊~
Single.zip(novel, rxJava2Tutorial, new BiFunction<IBook, IBook, List<IBook>>() {
@Override
public List<IBook> apply(IBook iBook, IBook iBook2) throws Exception {
List<IBook> books = new ArrayList<>(2);
books.add(iBook);
books.add(iBook2);
return books;
}
}).subscribe(new Consumer<List<IBook>>() {
@Override
public void accept(List<IBook> iBooks) throws Exception {
Logger.d(TAG, "test: books are " + iBooks);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Logger.d(TAG, "test: get books error.", throwable);
}
});
複製程式碼
上述程式碼分別讀取 Novel
和 RxJava2Tutorial
兩種不同型別書籍,再分別轉化為 IBook
型別,然後新增到同一陣列中,最後發射給下游。
zip(SingleSource source1, SingleSource source2, BiFunction zipper) [-> Single.java]
public static <T1, T2, R> Single<R> zip(
SingleSource<? extends T1> source1, SingleSource<? extends T2> source2,
BiFunction<? super T1, ? super T2, ? extends R> zipper
) {
ObjectHelper.requireNonNull(source1, "source1 is null");
ObjectHelper.requireNonNull(source2, "source2 is null");
return zipArray(Functions.toFunction(zipper), source1, source2);
}
複製程式碼
toFunction(BiFunction f) [-> Functions.java]
public static <T1, T2, R> Function<Object[], R> toFunction(final BiFunction<? super T1, ? super T2, ? extends R> f) {
ObjectHelper.requireNonNull(f, "f is null");
// 注意因為上面呼叫的是合併兩個 SingleSource 的方法,所以這裡呼叫的就是 Array2Func,2表示合併個數,像這樣的還有 Array3Func、Array4Func、... Array9Func
// 作用就是把多引數的 BiFunction 統一轉化為一個引數(Object[])的 Function 物件,呼叫的時候再把引數從 Object[] 裡取出來即可
return new Array2Func<T1, T2, R>(f);
}
複製程式碼
Array2Func [-> Functions::Array2Func]
static final class Array2Func<T1, T2, R> implements Function<Object[], R> {
final BiFunction<? super T1, ? super T2, ? extends R> f;
Array2Func(BiFunction<? super T1, ? super T2, ? extends R> f) {
this.f = f;
}
@SuppressWarnings("unchecked")
@Override
public R apply(Object[] a) throws Exception {
if (a.length != 2) {
throw new IllegalArgumentException("Array of size 2 expected but got " + a.length);
}
// 從 Object[] 中取出實參,然後呼叫實際的合併函式
return f.apply((T1)a[0], (T2)a[1]);
}
}
複製程式碼
zipArray(Function zipper, SingleSource... sources) [-> Single.java]
public static <T, R> Single<R> zipArray(Function<? super Object[], ? extends R> zipper, SingleSource<? extends T>... sources) {
ObjectHelper.requireNonNull(zipper, "zipper is null");
ObjectHelper.requireNonNull(sources, "sources is null");
if (sources.length == 0) {
return error(new NoSuchElementException());
}
return RxJavaPlugins.onAssembly(new SingleZipArray<T, R>(sources, zipper));
}
複製程式碼
SingleZipArray [-> SingleZipArray.java]
// 繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleZipArray<T, R> extends Single<R> {
// 用來儲存要合併的 SingleSource
final SingleSource<? extends T>[] sources;
// 用來儲存合併函式
final Function<? super Object[], ? extends R> zipper;
public SingleZipArray(SingleSource<? extends T>[] sources, Function<? super Object[], ? extends R> zipper) {
// 將 SingleSource 儲存為 this.sources
this.sources = sources;
// 將合併函式儲存為 this.zipper
this.zipper = zipper;
}
// 通過上面 subscribeOn 的原始碼分析可知,呼叫 subscribe() 時,便會呼叫到上游的 subscribeActual()
// 此處的 observer 同樣也是 ConsumerSingleObserver
@Override
protected void subscribeActual(SingleObserver<? super R> observer) {
SingleSource<? extends T>[] sources = this.sources;
int n = sources.length;
// 本示例合併的 SingleSource 個數為 2,即 n=2
if (n == 1) {
sources[0].subscribe(new SingleMap.MapSingleObserver<T, R>(observer, new SingletonArrayFunc()));
return;
}
// 將 ConsumerSingleObserver、SingleSource個數、合併函式封裝為 ZipCoordinator,用來等待所有
// SingleSource 都處理完,然後對其發射的值應用合併函式
ZipCoordinator<T, R> parent = new ZipCoordinator<T, R>(observer, n, zipper);
// 呼叫 ConsumerSingleObserver 的 onSubscribe()
observer.onSubscribe(parent);
// 一個 for 迴圈,挨個呼叫 SingleSource 的 subscribe(),觸發生產者開始生產
for (int i = 0; i < n; i++) {
if (parent.isDisposed()) {
return;
}
SingleSource<? extends T> source = sources[i];
if (source == null) {
parent.innerError(new NullPointerException("One of the sources is null"), i);
return;
}
source.subscribe(parent.observers[i]);
}
}
......
}
複製程式碼
ZipCoordinator [-> SingleZipArray::ZipCoordinator]
// 合併函式協調器,注意繼承自 AtomicInteger,以便採用計數法檢測是否所有的 SingleSource 都發射完畢
static final class ZipCoordinator<T, R> extends AtomicInteger implements Disposable {
private static final long serialVersionUID = -5556924161382950569L;
// 儲存下游觀察者,本示例此處為 ConsumerSingleObserver
final SingleObserver<? super R> actual;
// 儲存合併函式
final Function<? super Object[], ? extends R> zipper;
// SingleZipArray 的直接觀察者,用來分別接收每個 SingleSource 發射的結果
// 每收到一個值 (即每回撥一次 ZipSingleObserver 的 onSuccess()),計數值-1,直至計數值為0,說明全部發射完畢
final ZipSingleObserver<T>[] observers;
// 儲存每個 SingleSource 發射的結果
final Object[] values;
@SuppressWarnings("unchecked")
ZipCoordinator(SingleObserver<? super R> observer, int n, Function<? super Object[], ? extends R> zipper) {
// 因為繼承自 AtomicInteger,所以呼叫父類構造器,設定計數值
super(n);
// 將下游觀察者 ConsumerSingleObserver 儲存為 this.actual,用來接收合併後的結果
this.actual = observer;
// 將合併函式儲存為 this.zipper
this.zipper = zipper;
// 根據 SingleSource 的個數,生成相應個數的 SingleObserver,然後儲存為 this.observers
ZipSingleObserver<T>[] o = new ZipSingleObserver[n];
for (int i = 0; i < n; i++) {
o[i] = new ZipSingleObserver<T>(this, i);
}
this.observers = o;
// 根據 SingleSource 的個數,生成相應長度的 Object[],用來儲存它們發射的結果
this.values = new Object[n];
}
@Override
public boolean isDisposed() {
return get() <= 0;
}
@Override
public void dispose() {
if (getAndSet(0) > 0) {
for (ZipSingleObserver<?> d : observers) {
d.dispose();
}
}
}
// 上游呼叫 ZipSingleObserver::onSuccess() 時,便會呼叫該方法,觸發計數值-1
void innerSuccess(T value, int index) {
values[index] = value;
// 判斷計數值是否已減至零
if (decrementAndGet() == 0) {
// 計數值為0,說明 SingleSource 全部發射完畢,可以呼叫合併函式了
R v;
try {
// 呼叫合併函式,獲得合併後的結果
v = ObjectHelper.requireNonNull(zipper.apply(values), "The zipper returned a null value");
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
actual.onError(ex);
return;
}
// 將合併後的結果發射給下游,即 ConsumerSingleObserver
actual.onSuccess(v);
}
}
void disposeExcept(int index) {
ZipSingleObserver<T>[] observers = this.observers;
int n = observers.length;
for (int i = 0; i < index; i++) {
observers[i].dispose();
}
for (int i = index + 1; i < n; i++) {
observers[i].dispose();
}
}
void innerError(Throwable ex, int index) {
if (getAndSet(0) > 0) {
disposeExcept(index);
actual.onError(ex);
} else {
RxJavaPlugins.onError(ex);
}
}
}
複製程式碼
ZipSingleObserver [-> SingleZipArray::ZipSingleObserver]
// 用來接受 SingleSource 發射的結果
static final class ZipSingleObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T> {
private static final long serialVersionUID = 3323743579927613702L;
// zip 協調器,用來觸發計數值-1、計數值為0時呼叫合併函式併發射合併結果
final ZipCoordinator<T, ?> parent;
// 接受第幾個 SingleSource 的結果
final int index;
ZipSingleObserver(ZipCoordinator<T, ?> parent, int index) {
this.parent = parent;
this.index = index;
}
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.setOnce(this, d);
}
@Override
public void onSuccess(T value) {
// SingleSource 發射結果時,呼叫到這裡
// 呼叫 ZipCoordinator::innerSuccess()
parent.innerSuccess(value, index);
}
@Override
public void onError(Throwable e) {
// SingleSource 發射錯誤時,呼叫到這裡
// 呼叫 ZipCoordinator::innerError
parent.innerError(e, index);
}
}
複製程式碼
總結
類圖
設計思想
除了最上層的被觀察者和最下層的觀察者,中間的 Single 子類必有一與之對應的 SingleObserver 實現類,總結起來就是:
- 我的下游的下游不是我的下游
- 我的上游的上游不是我的上游
- 我只能訪問我的直接上游和直接下游
嗯,這大概可以起名叫 可非同步執行的責任鏈模式
。別搜了,這名字是我自己想的!