RxJava 相信各位已經使用了很久,但大部分人在剛學習 RxJava 感嘆切換執行緒的方便,呼叫邏輯清晰的同時,並不知道其中的原理,主要是靠記住執行的順序。
隨著我們設計出的 RxJava流 越來越複雜,一些複雜的問題並不能靠著記住的執行順序就能解決。
下面,就通過最常用的操作符的原始碼來看看所謂的流
是什麼執行的。
首先我們用Single
舉例,設計一個最基本的 RxJava 流,只有一個 Observable(ColdObservable)
和Obsever
:
Disposable disposable = Single.just("wtf")
.subscribe(it -> Log.i("subscribe", it));
複製程式碼
上游傳送一個"wtf"
,下游接受時將其列印出來。上游傳送端使用 Single.just
作為建立方法,
看一下 just()
方法裡做了什麼。
public static <T> Single<T> just(final T item) {
ObjectHelper.requireNonNull(item, "value is null");
return RxJavaPlugins.onAssembly(new SingleJust<T>(item));
}
public static <T> Single<T> onAssembly(@NonNull Single<T> source) {
Function<? super Single, ? extends Single> f = onSingleAssembly;
if (f != null) {
return apply(f, source);
}
return source;
}
複製程式碼
其中 ObjectHelper.requireNonNull
只是空檢查。
RxJavaPlugins.onAssembly
方法,這個方法其實就是通過一個全域性的變數 onSingleAssembly
來對方法進行 Hook ,這一系列xxxAssembly
全域性變數預設為空,所以實際上當我們沒有設定的時候其實 just
方法是直接返回了一個 新例項化的SingleJust
物件。
再看看SingleJust
內部:
public final class SingleJust<T> extends Single<T> {
final T value;
public SingleJust(T value) {
this.value = value;
}
@Override
protected void subscribeActual(SingleObserver<? super T> observer) {
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
}
}
複製程式碼
例項化的時候只是將值儲存了下來,沒有其它操作。
下一步呼叫subscribe()
來啟動這個流(ColdObservable)
,然後看看subscribe
中做了什麼:
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(subscriber);
} catch (NullPointerException ex) {
throw ex;
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
NullPointerException npe = new NullPointerException("subscribeActual failed");
npe.initCause(ex);
throw npe;
}
}
複製程式碼
同樣 RxJavaPlugins.onSubscribe
預設沒有作用,實際的核心邏輯是呼叫了subscribeActual(SingleObserver)
。
對於我們上面設計的流,則是呼叫了 SingleJust 中的 subscribeActual(SingleObserver)
回顧上面 SingleJust
中 subscribeActual(SingleObserver)
的實現:
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
複製程式碼
得到兩個資訊
- 首先呼叫下游觀察者
SingleObserver
的OnSubscribe
方法並傳遞用於取消操作的Disposable
- 呼叫
OnSuccess
方法並傳遞之前儲存下來的value
Map 操作符
現在我們加入一個常用且重要的Map
操作到流中
Disposable disposable = Single.just("wtf")
.map(it-> 0)
.subscribe(it -> Log.i("subscribe", String.of(it)));
複製程式碼
上面這個流包括了三種典型的操作 建立Creation
操作符Transformation
和 訂閱Subscribe
。
依然先檢查map()
方法,可以看到其中例項化了一個SingleMap
public final <R> Single<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new SingleMap<T, R>(this, mapper));
}
複製程式碼
再看看 SingleMap
public final class SingleMap<T, R> extends Single<R> {
final SingleSource<? extends T> source;
final Function<? super T, ? extends R> mapper;
public SingleMap(SingleSource<? extends T> source, Function<? super T, ? extends R> mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
protected void subscribeActual(final SingleObserver<? super R> t) {
source.subscribe(new MapSingleObserver<T, R>(t, mapper));
}
static final class MapSingleObserver<T, R> implements SingleObserver<T> {
final SingleObserver<? super R> t;
final Function<? super T, ? extends R> mapper;
MapSingleObserver(SingleObserver<? super R> t, Function<? super T, ? extends R> mapper) {
this.t = t;
this.mapper = mapper;
}
@Override
public void onSubscribe(Disposable d) {
t.onSubscribe(d);
}
@Override
public void onSuccess(T value) {
R v;
try {
v = ObjectHelper.requireNonNull(mapper.apply(value), "The mapper function returned a null value.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
onError(e);
return;
}
t.onSuccess(v);
}
@Override
public void onError(Throwable e) {
t.onError(e);
}
}
}
複製程式碼
類中資訊稍微複雜一些:
- 首先我們關注在
SingleMap
例項化的時候也是隻做了儲存資料的操作,而沒有實際邏輯:將流的上游儲存為source
將資料轉換的方法儲存為mapper
- 第二步我們知道下游觀察者
SingleObserver
會呼叫核心邏輯subscribeActual
方法來啟動流 - 在這裡的
subscribeActual
方法中可以看到幾個重要的資訊MapSingleObserver
是一個觀察者MapSingleObserver
儲存了下游的觀察者SingleObserver
以及mapper
- 上游
source
被MapSingleObserver
訂閱
由此可以看出在SingleMap
被下游觀察者訂閱了之後,例項化了一個新的觀察者MapSingleObserver
並儲存下游觀察者SingleObserver
的資訊,再去訂閱上游SingleJust
。
這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能的設計模式稱為裝飾者模式
。
總結上面的執行順序:
- 在
Rx流
的最後一步呼叫subscribe
啟動流(ColdObservable)
- 首先執行
SingleMap
中的subscribeActual
方法,其中包括生成新的MapSingleObserver
並訂閱SingleJust
- 執行
SingleJust
中的subscribeActual
:呼叫下游MapSingleObserver
的onSubscribe
onSuccess
方法 MapSingleObserver
中的onSubsribe``onSuccess
方法也很簡單,分別呼叫下游Observer
的onSubsribe``onSuccess(異常時 onError)
方法
observeOn 操作符
Rxjava首先被大家津津樂道之處是可以方便的切換執行緒,避免Callback Hell
,現在來看看執行緒切換操作符。
我們加入執行緒切換操作符 observeOn
Disposable disposable = Single.just("wtf")
.map(it-> 0)
.observeOn(Schedulers.io())
.subscribe(it -> Log.i("subscribe", String.of(it)));
複製程式碼
同樣的,在 observeOn
方法中例項化了一個SingleObserveOn
public final Single<T> observeOn(final Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new SingleObserveOn<T>(this, scheduler));
}
複製程式碼
繼續看SingleObserveOn
類中資訊
public final class SingleObserveOn<T> extends Single<T> {
final SingleSource<T> source;
final Scheduler scheduler;
public SingleObserveOn(SingleSource<T> source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver<? super T> s) {
source.subscribe(new ObserveOnSingleObserver<T>(s, scheduler));
}
static final class ObserveOnSingleObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, Runnable {
private static final long serialVersionUID = 3528003840217436037L;
final SingleObserver<? super T> actual;
final Scheduler scheduler;
T value;
Throwable error;
ObserveOnSingleObserver(SingleObserver<? super T> actual, Scheduler scheduler) {
this.actual = actual;
this.scheduler = scheduler;
}
@Override
public void onSubscribe(Disposable d) {
if (DisposableHelper.setOnce(this, d)) {
actual.onSubscribe(this);
}
}
@Override
public void onSuccess(T value) {
this.value = value;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
@Override
public void onError(Throwable e) {
this.error = e;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
@Override
public void run() {
Throwable ex = error;
if (ex != null) {
actual.onError(ex);
} else {
actual.onSuccess(value);
}
}
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
}
}
複製程式碼
類似的
- 建構函式中儲存了上游和執行緒切換的資訊
subscribeActual
例項化了一個新的觀察者ObserveOnSingleObserver
不同的
ObserveOnSingleObserver
還繼承了AtomicReference<Disposable>
、實現了Disposable``Runnable
介面onSuccess``onError
中都沒有直接呼叫下游的onSuccess``onError
方法,而是呼叫了Disposable d = scheduler.scheduleDirect(this);
來執行run
方法中的邏輯,而run
方法中的邏輯則是呼叫下游的onSuccess``onError
方法
檢視schedulerDirect
內部資訊
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
DisposeTask task = new DisposeTask(decoratedRun, w);
w.schedule(task, delay, unit);
return task;
}
複製程式碼
建立了一個對應執行緒的Worker
和一個可用於取消的DisposeTask
並執行,對於IoScheduler
則是建立了EventLoopWorker
,再看看EventLoopWorker
中的資訊。
@Override
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
複製程式碼
static final class EventLoopWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final CachedWorkerPool pool;
private final ThreadWorker threadWorker;
final AtomicBoolean once = new AtomicBoolean();
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
@Override
public void dispose() {
if (once.compareAndSet(false, true)) {
tasks.dispose();
// releasing the pool should be the last action
pool.release(threadWorker);
}
}
@Override
public boolean isDisposed() {
return once.get();
}
@NonNull
@Override
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
}
複製程式碼
EventLoopWorker
中則是維護了一套包含相應的執行緒池
、可取消的CompositeDisposable
、以及用於執行Runable
的ThreadWorker
。總的來說就是一套可以在相應執行緒執行且可取消的類和邏輯。
- 上面則解釋了為什麼
observeOn
可以切換下游的執行緒(onSuccess``onError
) - 同樣解釋了為什麼不會改變
onSubsribe
的呼叫執行緒,因為可以看到onSubscribe
方法中直接呼叫了下游的onSucsribe
,並沒有受到執行緒切換的影響。
SubscribeOn
現在設計兩個Rx流
Disposable disposable = Single.just("wtf")
.doOnSubsribe(it-> Log.i("doOnSubsribe", 0)
.doOnSubsribe(it-> Log.i("doOnSubsribe", 1)
.doOnSubsribe(it-> Log.i("doOnSubsribe", 2)
.doOnSubsribe(it-> Log.i("doOnSubsribe", 3)
.subscribe(it -> Log.i("subscribe", 4);
複製程式碼
Disposable disposable2 = Single.just("wtf")
.doOnSubsribe(it-> Log.i("doOnSubsribe", 0)
.doOnSubsribe(it-> Log.i("doOnSubsribe", 1)
.subscribeOn(Schedulers.io())
.doOnSubsribe(it-> Log.i("doOnSubsribe", 2)
.doOnSubsribe(it-> Log.i("doOnSubsribe", 3)
.subscribe(it -> Log.i("subscribe", 4);
複製程式碼
你可能已經知道並記住了兩個流的列印的順序分別是 01234``23014
,但是為什麼doOnSubsribe
方法和RxJava1
中呼叫順序完全不一樣,為什麼通過subscribeOn
切換執行緒會影響執行順序?
先找到 SingleSubscribeOn
類
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 = source;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s, source);
//直接呼叫下游 onSubscribe
s.onSubscribe(parent);
//再執行訂閱上游的方法
Disposable f = scheduler.scheduleDirect(parent);
parent.task.replace(f);
}
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 = actual;
this.source = source;
this.task = new SequentialDisposable();
}
@Override
public void onSubscribe(Disposable d) {
//沒有繼續呼叫下游的 onSubscribe 方法
DisposableHelper.setOnce(this, d);
}
@Override
public void onSuccess(T value) {
actual.onSuccess(value);
}
@Override
public void onError(Throwable e) {
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(this);
}
}
}
複製程式碼
同樣的直接看subscribeActual
方法及onSubscribe
方法,和之前的操作符的邏輯區別很大:
SubscribeOnObserver
同樣還繼承了AtomicReference<Disposable>
,實現了Disposable``Runnable
介面- 並沒有直接呼叫
subscribe
訂閱上游,而是執行了其它操作符在onSubscribe
中訂閱下游的操作 - 然後再結合
Disposable f = scheduler.scheduleDirect(parent);
和run
方法可以知道在新的執行緒中執行了訂閱上游的操作source.subscribe(this);
onSubsribe
中並沒有再繼續呼叫下游的onSubsribe
綜合起來可以知道,本來應該在整個流從下至上訂閱完成後按照從上至下的順序執行 onSubscribe
的流,在使用subsribeOn
操作符的後,在訂閱的時(執行subscribeActual
),就開始執行下游的onSubscribe
且在當前執行緒!然後才在指定的io
執行緒執行之下而上的操作,這也是為什麼subsribeOn
影響的是上游的執行緒。
小結:
我認為實際上 Rx 使用了很多優秀的設計將我們各種常用的操作進行了封裝,讓我們自由組合使用,其本身並沒有用什麼黑科技。例如切換執行緒本質上則是幫我們啟用了一個新的執行緒並把接下來的程式碼放進去執行。
當然,其中還有很多更深入的內容需要我們繼續發現和學習。