RxJava如何結合觀察者與鏈式處理
Author: Dorae
Date: 2018年12月3日17:10:31轉載請註明出處
一、概述
首先問自己幾個問題,如果非常清楚這幾個問題的目的與答案,那麼恭喜你,不用繼續往下看了-_-。
- RxJava是幹什麼的;
- 鏈式呼叫中當存在數個Observable.subscribeOn()時的處理方式;
- 鏈式呼叫中當存在數個Observable.observeOn()時的處理方式;
- 資料是如何經過操作符進行的處理。
回顧
觀察者模式
如圖1-1所示
Java8的stream
二、RxJava是什麼
一款為了簡化非同步呼叫,且功能比較全面的框架。
三、RxJava如何結合了觀察者模式與鏈式處理
參見Java8中的sink鏈,在RxJava中同樣實現了鏈式處理。如程式碼片段code1-1所示,我們對其結構進行分析:
code1-1
Observable.create(new ObservableOnSubscribe<
String>
() {
@Override public void subscribe(ObservableEmitter<
String>
emitter) throws Exception {
emitter.onNext("Dorae");
}
}) .filter(e ->
e.contains("o")) .map(e ->
"AfterMap: " + e) .filter(e ->
e.contains("D")) .subscribe(new Observer<
String>
() {
@Override public void onNext(@NonNull String o) {
System.out.println("觀察者 onNext: " + o);
} @Override public void onSubscribe(Disposable d) {
System.out.println("觀察者onSubscribe: " + d + "### " + Thread.currentThread().getName());
} @Override public void onError(Throwable e) {
} @Override public void onComplete() {
}
});
複製程式碼
1、首先看下其輸出結果:
觀察者onSubscribe: io.reactivex.internal.operators.observable.ObservableFilter$FilterObserver@52d455b8### main
觀察者 onNext: AfterMap: Dorae
2、現在來對如何輸出這段結果進行分析
首先了解下RxJava中的幾種基本角色:
- Observable,是RxJava描述的事件流,可以說其與Observer構成了RxJava的基礎。在鏈式呼叫中,事件從建立到加工到最後被Observer接受,其實就是由一條Observerable鏈串起來的。
- Observer,RxJava中的訂閱者,也就是需要對事件進行響應的一個角色。其實除了我們通常自己實現的一個Observer,在鏈中的每一步都會產生一個Observer,然後這些Observer構成一條鏈,最終完成整個鏈的計算。
- ObservableOnSubscribe,整個事件流的源頭,通常需要我們自己實現,其依賴一個Emitter。
- Emitter,可以將其理解為觸發器,推動整個流程的運轉。
- Scheduler,這個其實不用太過關心,RxJava用其封裝了Thread,用於完成執行緒切換等任務。
是不是感覺上邊的一堆廢話非常枯燥?先上一張RxJava的核心結構,如圖3-1所示。
現在我們再來看看code1-1,其最終形成的Observable鏈如圖3-2所示,每次呼叫map、filter等操作,都會生成一個新物件,並且保持了一個對上游的引用(用於生成Observer鏈)。
Observer鏈如圖3-3所示,整個事件流程由CreateEmitter觸發,最終交由我們的實現Observer$1處理。
看了上邊幾張圖之後,是不是感覺清晰了很多?那麼讓我們進一步看下Rxjava如何完成了一鍵執行緒切換。
四、RxJava如何實現執行緒切換
通常我們使用RxJava的執行緒切換功能時,只需要在呼叫鏈中加上一句subscribeOn()或observeOn(),其中Scheduler如上所述,其實就是一個包裝了ThreadPool的排程器。那麼我們先來看下相關原始碼。
1、subscribeOn
如程式碼code4-1所示,為subscribeOn的核心程式碼。很明顯,其中在新執行緒中只是簡單的直接呼叫了source,也就是說這裡之後的所有操作均在一個新執行緒中進行,和單執行緒並沒有什麼區別。
code 4-1
public final Observable<
T>
subscribeOn(Scheduler scheduler) {
return new ObservableSubscribeOn<
T>
() {
@Override public void subscribeActual(final Observer<
? super T>
observer) {
scheduler.createWorker().schedule(new SubscribeTask() {
@Override public void run() {
source.subscribe(e);
}
});
}
};
}複製程式碼
2、observeOn
如程式碼段code4-2所示,為observeOn的核心邏輯,可以看出其在訂閱階段(生成Observer鏈的階段)還是在當前執行緒執行,只有觸發之後,到了ObserverOn的Observer的節點時才會真正的切換到新執行緒。
code 4-2
public final Observable<
T>
observeOn(Scheduler scheduler) {
return new ObservableOnSubscribe<
T>
() {
@Override public void subscribeActual(@NonNull Observer<
Object>
e) {
source.subscribe(new Observer<
T>
() {
@Override public void onNext(T var1) {
scheduler.createWorker().schedule(new Runnable() {
@Override public void run() {
e.onNext(var1);
}
});
}
});
}
};
}複製程式碼
多次Observable.subscribeOn()、多次Observable.observeOn()會發生什麼
通過上述code4-1、code4-2的分析,是不是可以推斷出當多次subscribeOn時會發生什麼?沒錯,雖然每次subscribeOn都會產生一次執行緒切換,但是真正起作用的只有最開始的一次subscribeOn,也就相當於只在最初的位置呼叫了subscribeOn;對於observeOn也是類似,每次都會產生新執行緒,但是每次都會產生一定的影響,也就是每個執行緒都承擔了一部分工作。
小結
通過本文,我們可以簡要了解到RxJava的基本原理,但是對於其豐富的api還需要在實踐中進行磨合。但是,RxJava既然作為一個非同步框架,其必然有一定的侷限,比如其切換執行緒時無法阻塞當前執行緒(這種對於Android等需要渲染或者網路IO的需求來說非常適用),但是對於常見的服務端業務來說,還需要額外引入阻塞當前執行緒的操作(因為大部分的server程式碼還是單執行緒模型),倘若完全不用執行緒切換在服務端強行引入,可能會得不償失。個人更推薦Java8的CompletableFuture。