不忘初心 砥礪前行, Tomorrow Is Another Day !
本文概要:
- Observable的建立
- subscribe訂閱過程
- 傳送事件
- 執行緒切換過程
1. Observable的建立
對應原始碼
//Observable.java
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
//引數檢查
ObjectHelper.requireNonNull(source, "source is null");
//裝配Observable,返回一個ObservableCreate物件
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
//鉤子方法
@NonNull
public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
Function<? super Observable, ? extends Observable> f = onObservableAssembly;
if (f != null) {
return apply(f, source);
}
return source;
}
@NonNull
static <T, R> R apply(@NonNull Function<T, R> f, @NonNull T t) {
try {
return f.apply(t);
} catch (Throwable ex) {
throw ExceptionHelper.wrapOrThrow(ex);
}
}
複製程式碼
當我們通過Create方法建立一個Observable物件時,
- 引數檢查,然後裝配Observable,返回一個ObservableCreate物件,它持有一個ObservableOnSubscribe物件,ObservableCreate是Observable的子類
- 裝配流程: 執行鉤子方法,對即將建立的Observale進行預處理,可以通過onObservableAssembly進行設定.
2. subscribe訂閱過程
當我們建立完Observable物件時,會呼叫subscribe去繫結觀察者Observer.所以直接看該方法.
對應原始碼
//Observable.java
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
subscribeActual(observer);//此方法是重中之重.
} catch (NullPointerException e) { // NOPMD
throw e;
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// can't call onError because no way to know if a Disposable has been set or not
// can't call onSubscribe because the call might have set a Subscription already
RxJavaPlugins.onError(e);
NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
npe.initCause(e);
throw npe;
}
}
複製程式碼
同樣的方式,對我們傳入的Observer觀察者物件進行檢查以及預處理,最終呼叫subscribeActual方法,該方法是一個抽象方法.所以我們直接看它的實現類,也就是ObservableCreate物件下的subscribeActual方法.
對應原始碼
//ObservableCreate.java
public ObservableCreate(ObservableOnSubscribe<T> source) {
this.source = source;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
//1. 建立一個發射器物件
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//2. 回撥onSubscribe,通知訂閱成功
observer.onSubscribe(parent);
try {
//3. 回撥subscribe,開始傳送事件.
//source物件就是建立被觀察者傳入的.
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
複製程式碼
上面註釋已經寫得很詳細了這裡再重複一次.整個訂閱過程就是.
- 建立一個發射器物件,繫結觀察者Observer
- 回撥onSubscribe,通知訂閱成功
- 回撥subscribe,開始傳送事件
接著我們來看發射器物件CreateEmitter是如何將事件傳送給訂閱者的.
3. 傳送事件
對應原始碼
//ObservableCreate#CreateEmitter.java
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {
private static final long serialVersionUID = -3434801548987643227L;
final Observer<? super T> observer;
CreateEmitter(Observer<? super T> observer) {
this.observer = observer;
}
@Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
if (!isDisposed()) {
//回撥onNext
observer.onNext(t);
}
}
@Override
public void onError(Throwable t) {
if (!tryOnError(t)) {
RxJavaPlugins.onError(t);
}
}
@Override
public boolean tryOnError(Throwable t) {
if (t == null) {
t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
}
if (!isDisposed()) {
try {
//回撥onError
observer.onError(t);
} finally {
//最後斷開訂閱
dispose();
}
return true;
}
return false;
}
@Override
public void onComplete() {
if (!isDisposed()) {
try {
//回撥onComplete.
observer.onComplete();
} finally {
//最後斷開訂閱
dispose();
}
}
}
@Override
public void setDisposable(Disposable d) {
DisposableHelper.set(this, d);
}
@Override
public void setCancellable(Cancellable c) {
setDisposable(new CancellableDisposable(c));
}
@Override
public ObservableEmitter<T> serialize() {
return new SerializedEmitter<T>(this);
}
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
}
//DisposableHelper.java
//斷開訂閱方法
public static boolean dispose(AtomicReference<Disposable> field) {
Disposable current = field.get();
Disposable d = DISPOSED;
if (current != d) {
current = field.getAndSet(d);
if (current != d) {
if (current != null) {
current.dispose();
}
return true;
}
}
return false;
}
複製程式碼
從上面註釋可知,發射器CreateEmitter直接回撥了觀察者Observer的相關方法.當呼叫dispose斷開dispose訂閱時,此時和執行緒中斷處理一樣,僅僅只是作為一個標識,標識當前發射器已經被中斷.
這裡最後給出一張關係圖對上面流程進行歸納.
4. subscribeOn過程
從上面可知,RxJava的整體流程框架還是挺清晰的,但有時我們需要多它進行一些附加的操作如切執行緒,map,filter進行轉換等.這裡以切執行緒為例進行分析看如何工作的.
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
//新建一個ObservableSubscribeOn.
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
複製程式碼
當我們切換下游執行緒時,也返回了一個新建的Observable-ObservableSubscribeOn.接著我們直接看ObservableSubscribeOn類.
對應原始碼
//ObservableSubscribeOn.java
//中間的Observable.
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);//上游的源Observable
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> s) {
//建立一箇中間的Observer
//建立一箇中間的Observer
//建立一箇中間的Observer
//重要的話說三遍.
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//回撥onSubscribe,通知訂閱成功
s.onSubscribe(parent);
//切換執行緒
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
//執行緒任務類SubscribeTask
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
//回撥subscribe,進行訂閱
//source是源Observable,parent則是中間Observer,不是最終目標的Observer.這裡一定要清楚.
source.subscribe(parent);
}
}
複製程式碼
從上面註釋可知,當我們呼叫subscribeOn切換上游執行緒時
- 建立一箇中間的Observable,然後在這個Observable裡面會建立一箇中間的Observer
- 最後線上程任務的run方法裡面通過將源Observable與中間的Observer進行繫結訂閱,從而進行切換了上游執行緒.
- 中間的Observer接到相應回撥時則會繼續往上回撥源Observer.
這也就是解釋了最開始文章所說的subscribeOn無論呼叫幾次,為什麼只有第一次是生效的.因為每次都建立新的Observable與Observer,執行緒排程器裡將源Observable與中間的Observer進行繫結訂閱時,源Observable僅僅是指上一個,已經不是第一個建立出來的.
通過上面流程分析可以總結出RxJava操作符一些通用的流程.對於Map等操作符都可以參考.如圖
5. observeOn過程
最後我們根據上面總結出的通用流程,去分析下切換下游執行緒的過程.
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
//返回一個新建的Observable
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}
複製程式碼
同樣當呼叫observeOn過程切換下游執行緒時,果不其然也返回了一箇中間的Observable-ObservableObserveOn.接著看ObservableObserveOn程式碼.
對應原始碼
//中間的Observable
//ObservableObserveOn.java
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
//執行緒排程器
Scheduler.Worker w = scheduler.createWorker();
//回撥subscribe進行訂閱(中間的Observer-ObserveOnObserver)
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
複製程式碼
同樣,果不其然
- 建立了一箇中間的Observer-ObserveOnObserver,這個中間的Observer繫結了執行緒排程器Scheduler.
- 接著將源Observable與它繫結訂閱.
- 最後接收到事件時,則通過中間Observer的執行緒排程器去回撥目標Observer.
之前我們知道每次執行observeOn都會切換一次下游執行緒,從上面原始碼可知,每次都會新建一箇中間的Observer繫結新指定的執行緒排程器,所以接收事件都是在新的執行緒中執行啦.
至此,RxJava基本原理就差不多分析完成,最重要的是記住兩張流程圖,都遵循這個規律.
由於本人技術有限,如有錯誤的地方,麻煩大家給我提出來,本人不勝感激,大家一起學習進步.