RxJava——目前最熱門的響應式函數(shù)編程框架。
筆者也是初涉Rx,所以打算通過這篇文章來理解Rx的操作流程,加深自己對Rx的理解。
本文不涉及RxJava的入門使用,如有需有:
關于RxJava的入門推薦:拋物線大佬的精品——給 Android 開發(fā)者的 RxJava 詳解
[筆者仍為Android初學者。如有解釋錯誤的地方,歡迎評論區(qū)指正探討]
本文主要根據(jù)RxJava2的源碼解析整個流程。
引入
首先簡單的看一下關于RxJava的一般使用:
前提:定義了一個login接口,返回值為 { isSuccess, UserInfo}
Observable.create(new ObservableOnSubscribe<LoginApiResult>() {
@Override
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
}) //調(diào)用登錄接口
.map(new Function<LoginApiBean, UserInfoBean>() {
@Override
protected UserInfoBean decode(LoginApiBean loginApiBean) {
//處理登錄結(jié)果,返回UserInfo
if (loginApiBean.isSuccess()) {
return loginApiBean.getUserInfoBean();
} else {
throw new RequestFailException("獲取網(wǎng)絡請求失敗");
}
}
})
.doOnNext(new Consumer<UserInfoBean>() { //保存登錄結(jié)果UserInfo
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {
saveUserInfo(bean);
}
})
.subscribeOn(Schedulers.io()) //調(diào)度線程
.observeOn(AndroidSchedulers.mainThread()) //調(diào)度線程
.subscribe(new Consumer<UserInfoBean>() {
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {LoginApiBean
//整個請求成功,根據(jù)獲取的UserInfo更新對應的View
showSuccessView(bean);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
//請求失敗,顯示對應的View
showFailView();
}
});
為了便于理解,上述邏輯沒有對應的進行封裝,簡單的展示 RxJava 的幾個重要流程。
按著代碼的順序我們理一下步驟:
首先是通過create方法,生成一個Observable對象,并傳入一個ObservableOnSubscribe對象,在其回調(diào)方法中調(diào)用login接口返回LoginApiResult,并執(zhí)行onNext
然后通過map方法將LoginApiResult轉(zhuǎn)換成UserInfoBean
緊接著是通過doOnNext方法進行保存saveUserInfo操作
然后是線程的調(diào)度,分別通過subscribeOn和observeOn將上面提到的步驟都執(zhí)行在IO線程,下面的步驟都執(zhí)行在主(UI)線程中
最后是通過Consumer根據(jù)執(zhí)行結(jié)果完成(成功或拋異常),執(zhí)行對應的UI更新方法。
按著順序,我們一步一步的跟進看看RxJava到底是如何實現(xiàn)這些操作的。
任務鏈的構(gòu)建
入口類——Observable
既然要了解RxJava,那么比不可少的我們應該先來看看他的入口類,也就是Observable:
public abstract class Observable<T> implements ObservableSource<T> {
@Override //交由子類實現(xiàn)的出現(xiàn)方法
protected abstract void subscribeActual(Observer observer) ;
@Override //實現(xiàn)了ObservableSource的方法
public final void subscribe(Observer<? super T> observer) {
//省略一堆判空等處理
subscribeActual(observer);
}
省略了一堆靜態(tài)方法之后,我們可以看到,Observable是一個抽象類,實現(xiàn)了ObservableSource接口,并留了subscribeActual這個抽象方法。
ObservableSource接口只定義了subscribe一個方法,可以看到這個方法做了一些基礎判斷之后直接跳轉(zhuǎn)到子類的subscribeActual方法。
所以一個被觀察者被subscribe的邏輯其實是交由Observable子類來實現(xiàn)的,每個不同的被觀察者可以根據(jù)自己的需求實現(xiàn) "被訂閱" 后的操作
(賊拗口- -md,總覺得這里用subscribe這個命名很奇怪,還是setSubscriber好懂)
(換而言之,每個子類可以實現(xiàn)各自被setSubscriber后的動作)
Create
接下來是如何生成一個Obserable對象,我們看到create方法。
create方法便是Obserable其中一個關鍵的靜態(tài)方法。
我們跟進看一下源碼:
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
首先第一句代碼是對傳入的對象進行判空,內(nèi)部內(nèi)部實現(xiàn)是如果傳入null,會拋異常。
接著是生成一個ObservableCreate對象,然后將這個對象傳入RxJavaPlugins進行組裝。
RxJavaPlugins提供了一系列的Hook function,通過鉤子函數(shù)這種方法對RxJava的標準操作進行加工,當我們沒有進行配置時,默認是直接返回原來的對象,也就是返回ObservableCreate對象。
(為了方便講解,后續(xù)將直接忽視判空和RxJavaPlugins的代碼)
分析后可以看到,這里其實直接返回一個ObservableCreate對象。
我們跟進去看一下這個對象的一些基本信息:
public final class ObservableCreate<T> extends Observable<T> {
final ObservableOnSubscribe<T> source;
public ObservableCreate(ObservableOnSubscribe<T> source) {
this.source = source;
}
可以簡單的看到,這個類繼承了Observalbe類,并存儲了我們剛才傳進去的ObservableOnSubscribe對象。當然這個類也實現(xiàn)了剛才說的subscribeActual方法,我們待會再看。
map
往下,我們調(diào)用了Obserable的map方法:
我們跟進:
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
return new ObservableMap<T, R>(this, mapper);
}
可以看到其實是返回了一個ObservableMap對象,接受了兩個參數(shù),一個是this,在這里指的也就是剛才的ObservableCreate ,還有一個Function對象,
我們再跟進去看一下ObservableMap的基礎信息:
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;
}
可以看到其實構(gòu)造方法和剛才的ObservableCreate一樣,將傳入的對象進行了存儲。
不過可以發(fā)現(xiàn)- -這個類并不是繼承自Observable,而是AbstractObservableWithUpstream,我們再跟進看看:
// Base class for operators with a source consumable.
// 帶有source的operator的基類
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {
/** The source consumable Observable. */
protected final ObservableSource<T> source;
AbstractObservableWithUpstream(ObservableSource<T> source) {
this.source = source;
}
@Override
public final ObservableSource<T> source() {
return source;
}
}
可以看到這個父類其實繼承了Observable,看到官方的注釋可以知道,這個類是所有接受上一級輸入的操作符(operator 如map)的基類,這里的邏輯并復雜,其實只是簡單的封裝了一下上一級的輸入source和輸出先下一級的數(shù)據(jù)。
分析之后可以看到,調(diào)用了map方法其實也是返回了一個Observable對象。
doOnNext
接著往下是doOnNext,- -看到這里可以猜測也是簡單的返回一個Observable對象吧。。
不管怎么說,先進入源碼看一看:
public final Observable<T> doOnNext(Consumer<? super T> onNext) {
return doOnEach(onNext, Functions.emptyConsumer(), Functions.EMPTY_ACTION, Functions.EMPTY_ACTION);
}
private Observable<T> doOnEach(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Action onAfterTerminate) {
return new ObservableDoOnEach<T>(this, onNext, onError, onComplete, onAfterTerminate);
}
可以看到跳轉(zhuǎn)到doOnEach方法,傳入的參數(shù)除了我們傳進來的Consumer之外,其實都是傳了空實現(xiàn)的Consumer對象。
可以看到- -真的是簡單的返回一個Observable對象。
老規(guī)矩,先看一下ObservableDoOnEach的基礎信息:
public final class ObservableDoOnEach<T> extends AbstractObservableWithUpstream<T, T> {
final Consumer<? super T> onNext;
final Consumer<? super Throwable> onError;
final Action onComplete;
final Action onAfterTerminate;
public ObservableDoOnEach(ObservableSource<T> source, Consumer<? super T> onNext,
Consumer<? super Throwable> onError,
Action onComplete,
Action onAfterTerminate) {
super(source);
this.onNext = onNext;
this.onError = onError;
this.onComplete = onComplete;
this.onAfterTerminate = onAfterTerminate;
}
同樣的對所有信息進行了保存。可以看到這個類也是繼承了AbstractObservableWithUpstream,可以接受上一層的輸入,并向下一層輸出數(shù)據(jù)。
subscribeOn & observeOn
= =接著是線程調(diào)度,其實不看也猜得出。。。這里也是直接返回對應的Observable對象。
首先看一下subscribeOn:
public final Observable<T> subscribeOn(Scheduler scheduler) {
return new ObservableSubscribeOn<T>(this, scheduler);
}
再看一下ObserveOn:
public final Observable<T> observeOn(Scheduler scheduler) {
return observeOn(scheduler, false, bufferSize());
}
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
return new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize);
}
可以看到,這里分別返回了0ObservableSubscribeOn和ObservableObserveOn對象。照舊我們先看看這兩個個類的基礎信息:
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 final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
final boolean delayError;
final int bufferSize;
public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
super(source);
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
同樣的保存了傳進去的基礎信息,我們發(fā)現(xiàn)其中共有的都保存了Scheduler對象,我們先稍微看一下Scheduler:
public abstract class Scheduler {
@NonNull
public abstract Worker createWorker();
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
w.schedule(new Runnable() {
@Override
public void run() {
try {
run.run();
} finally {
w.dispose();
}
}
}, delay, unit);
return w;
}
public abstract static class Worker implements Disposable {
@NonNull
public Disposable schedule(@NonNull Runnable run) {
return schedule(run, 0L, TimeUnit.NANOSECONDS);
}
@NonNull
public abstract Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit);
}
可以看到,Scheduler對外暴露了scheduleDirect方法,這個方法通過調(diào)用抽象方法createWorker得到worker對象,然后調(diào)用worker對象的schedule方法,執(zhí)行runnable。
看到這里大致就能猜出Scheduler對應的邏輯啦,內(nèi)部的worker對象維護自己的線程池,然后每次執(zhí)行schedule方法時把runnable對象提交到線程池中。先這樣理解,最后我們再深入一下。
subscribe
終于來到最后這個方法了- -md。。。前面全都是直接返回對象,難道所有邏輯都在最后實現(xiàn)嗎?- -進去看一下先。
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {
LambdaObserver<T> ls = new LambdaObserver<T>(onNext, onError, onComplete, onSubscribe);
subscribe(ls);
return ls;
}
public final void subscribe(Observer<? super T> observer) {
subscribeActual(observer);
因為subscribe的重載方法很多- -這里只挑最終的兩個,其中LambdaObserver其實就是把傳進來的Consumer包裝成一個Observer(看清不是Observable!Observer是訂閱者),內(nèi)部就是簡單的在各個階段調(diào)用我們傳進去的Consumer的accpet方法。
Observer其實只是個接口,里面定義了接收到被觀察者(Observable)發(fā)出的事件時,訂閱者(Observer)應該執(zhí)行的方法:
public interface Observer<T> {
void onSubscribe(Disposable d);
void onNext(T t);
void onError(Throwable e);
void onComplete();
}
接著就是直接調(diào)用了subscribeActual方法。剛才我們在上述的步驟也說了,這個方法是Observable的抽象方法。
其實到這里我們可以看出,整個步驟通過對象的嵌套,形成了一條完整的鏈。
逆向逐級訂閱
跟蹤subscribe
按照我們剛才的案例,到最后subscribe
方法的調(diào)用關系應該是這樣的:
ObservableObserveOn.subscribe(LambdaObserver)。
所以我們跟進看一下ObservableObserveOn.subscribe方法的實現(xiàn):
@Override
protected void subscribeActual(Observer<? super T> observer) {
//省略部分代碼
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
可以看到,這里通過Scheduler創(chuàng)建了一個wroker對象,然后調(diào)用了source(上一級)的subscribe方法,并通過已有的observer對象生成一個ObserveOnObserver(注意是Observer)對象作為傳參。
看到這里也大概知道套路了= =和剛才一樣,會一直沿著整條鏈返回,一個一個訂閱對應Observable并生成新的嵌套的Observer。
我們依舊跟著看看,ObservableObserveOn.subscribe之后是ObservableSubscribeOn.subscribe:
@Override
public void subscribeActual(final Observer<? super T> s) {
//將上一級傳進來的訂閱者包裝為線程安全的原子變量
//SubscribeOnObserver只是簡單的包裝,這里不展開
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//先在當前線程執(zhí)行訂閱者的onSubscribe方法
s.onSubscribe(parent);
//然后在指定的線程中執(zhí)行source(上一級)的subscribe
parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
source.subscribe(parent);
}
}));
}
根據(jù)我們最開始的業(yè)務邏輯,我們這里的scheduler應該對應IO線程,也就是說往下執(zhí)行的subscribe操作都是執(zhí)行再IO線程中的。(現(xiàn)在是逆向遍歷剛才建立的observable鏈。)
緊接著ObservableDoOnEach.subscribe:
@Override
public void subscribeActual(Observer<? super T> t) {
source.subscribe(new ObservableDoOnEach.DoOnEachObserver<T>(t, onNext, onError, onComplete, onAfterTerminate));
}
可以看到,這里也是封裝了我們傳進去的Consumer參數(shù),直接調(diào)用了上一級的source.subscribe方法。
= =那么就接著往下看。應該來到了ObservableMap.subscribe方法了。
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new ObservableMap.MapObserver<T, U>(t, function));
}
可以看到也是封裝了我們傳進去的Function參數(shù),然后調(diào)用上一級source.subscribe,也就是ObservableCreate.subscribe,也就到了鏈的一開始。
我們跟進看看ObservableCreate.subscribe:
@Override
protected void subscribeActual(Observer<? super T> observer) {
//首先是創(chuàng)建了CreateEmitter對象,這個類有沒有覺得特別眼熟- -
ObservableCreate.CreateEmitter<T> parent = new ObservableCreate.CreateEmitter<T>(observer);
//然后調(diào)用了訂閱者observer的onSubscribe方法
//這里的訂閱者來自剛才的map操作
observer.onSubscribe(parent);
try {
//調(diào)用上一級source的subscribe方法
//顯然- -沒有上一級了,這里的source就是我們一開始創(chuàng)建的observer對象,調(diào)用的subscribe方法也就是我們調(diào)用的login()方法的地方
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
//捕獲異常
parent.onError(ex);
}
}
終于回到了第一級,可以看到,一樣的封裝了observer訂閱者,(這里的訂閱者來自map操作),然后調(diào)用了source.subscribe方法,(- -看到這里不知道你們還記不記得source來自哪- -看下面代碼)這個source來自我們一開始調(diào)用Observable.create時傳進來的參數(shù),而subscribe方法就是我們一開始執(zhí)行l(wèi)ogin()方法的地方。
Observable.create(new ObservableOnSubscribe<LoginApiResult>() {
@Override
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
}) //調(diào)用登錄接口
……省略
也就是說,在剛才所有的逆序遍歷過程中,下一級的Observable會生成的對應的Observer訂閱上一級的source。
執(zhí)行任務鏈
接下來就是激動人心的執(zhí)行我們定義的任務了。(md終于- -)
= =在分析前,先重新看一下我們剛才的業(yè)務邏輯:
Observable.create(new ObservableOnSubscribe<LoginApiResult>() {
@Override
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
}) //調(diào)用登錄接口
.map(new Function<LoginApiBean, UserInfoBean>() {
@Override
protected UserInfoBean decode(LoginApiBean loginApiBean) {
//處理登錄結(jié)果,返回UserInfo
if (loginApiBean.isSuccess()) {
return loginApiBean.getUserInfoBean();
} else {
throw new RequestFailException("獲取網(wǎng)絡請求失敗");
}
}
})
.doOnNext(new Consumer<UserInfoBean>() { //保存登錄結(jié)果UserInfo
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {
saveUserInfo(bean);
}
})
.subscribeOn(Schedulers.io()) //調(diào)度線程
.observeOn(AndroidSchedulers.mainThread()) //調(diào)度線程
.subscribe(new Consumer<UserInfoBean>() {
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {LoginApiBean
//整個請求成功,根據(jù)獲取的UserInfo更新對應的View
showSuccessView(bean);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
//請求失敗,顯示對應的View
showFailView();
}
});
一趟創(chuàng)建,一趟逆向訂閱,我們又回到了最開始的地方。我們剛才分析到,ObservableCreate會執(zhí)行我們定義的方法。
所以就來到了這段代碼:
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
行- -就是login,就是調(diào)用ObservableEmitter.onNext方法。我們跟進:
public final class ObservableCreate<T> extends Observable<T> {
protected void subscribeActual(Observer<? super T> observer) {
//可以看到,這里傳入的Observer參數(shù)是來自下一級的訂閱者
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//省略一堆- -
}
//省略繼承關系
static final class CreateEmitter<T> {
//保存訂閱者
CreateEmitter(Observer<? super T> observer) {
this.observer = observer;
}
@Override
public void onNext(T t) {
//省略判空
if (!isDisposed()) {
//調(diào)用訂閱者的onNext方法
observer.onNext(t);
}
}
}
}
可以看到吧,簡單的執(zhí)行一些判斷后,就調(diào)用了訂閱者的onNext方法,而通過上面的代碼,我們可以看到observer來自于subscribe時調(diào)用構(gòu)造函數(shù)的傳參,而通過上述的分析,我們知道,這里的訂閱者來自下一級,也就是map操作生成的訂閱者。這里很自然的進入了map操作。
(后面不再貼出observer的來源)
我們再往下看到MapObserver:
@Override
public void onNext(T t) {
//省略一些細節(jié)上的判斷
U v;
//mapper就是我們new 的function對象
v = mapper.apply(t)
actual.onNext(v);
}
可以看到,這里調(diào)用了我們定義的apply方法,獲得了新的對象,然后調(diào)用了下一級訂閱者的onNext方法。
嘿嘿嘿看到這里大概就知道執(zhí)行任務鏈的套路了。嵌套的調(diào)用下一級的onNext方法。
我們先繼續(xù)往下看,來到了DoOnEachObserver中:
@Override
public void onNext(T t) {
onNext.accept(t);
actual.onNext(t);
}
bingo!基本上和我們猜想的一樣~accept方法就是我們定義的doOnNext的操作啊~
再接著往下來到SubscribeOnObserver:
@Override
public void onNext(T t) {
actual.onNext(t);
}
這貨更直接。。直接就調(diào)過去了- -(這里涉及到Scheduler的線程調(diào)度,后面再補充)
快到重點了,再看一下ObserveOnObserver:
@Override
public void onNext(T t) {
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
擦,這貨邏輯賊復雜。。畢竟在這里進行了線程調(diào)度。暫時不深入。
只需要知道:這貨把任務提交給了Scheduler中的worker。等到任務結(jié)束獲取到結(jié)果后會調(diào)用下一級的onNext方法。
強行來到最后一層了~
這里的Observer就是我們調(diào)用subscribe時傳入的Observer啦~
那就是調(diào)用:
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {LoginApiBean
//整個請求成功,根據(jù)獲取的UserInfo更新對應的View
showSuccessView(bean);
}
行了- -走完整個流程了。。相信看到這里就能大致理解Rx的流程怎么走了(也沒有想象的那么復雜嘛~)
在剛才的遍歷訂閱后,每一步操作都會通知對應的Observer,從而完成整調(diào)任務鏈。
執(zhí)行任務鏈.png
總結(jié)
總結(jié)一下:
- 創(chuàng)建任務鏈,每一步都會返回對應的Observable對象。
- 逆向逐級訂閱。每一步都會生成對應的Observer對上一步生成的Observable進行訂閱
- 執(zhí)行任務鏈。執(zhí)行任務鏈之后,每一步都會通知對應的Observer,從而完成整調(diào)任務鏈。
嘿嘿嘿,感覺整個流程也沒有想想中的難~對Rx的理解又更上一層了。
= =呃。寫到這發(fā)現(xiàn)篇幅略長。Scheduler的解析還是另起一篇文章吧,挖個坑先。
[筆者仍為Android初學者。如有解釋錯誤的地方,歡迎評論區(qū)指正探討]