在上一篇文章RxJava2筆記(一、事件訂閱流程)中,我們講解了RxJava的事件訂閱流程,本文我們將繼續(xù)講解RxJava的訂閱取消流程。
我們對上一篇文章開始的代碼做一些修改:
private Disposable disposable;
private void init() {
Observer<Integer> observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "onSubscribe:");
disposable = d;
}
@Override
public void onNext(Integer integer) {
Log.i(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: " + e.getMessage());
e.printStackTrace();
}
@Override
public void onComplete() {
Log.i(TAG, "onComplete:");
}
};
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) {
emitter.onNext(1);
emitter.onNext(2);
disposable.dispose();
emitter.onNext(3);
emitter.onComplete();
}
}).subscribe(observer);
}
我們在emitter.onNext(2)和emitter.onNext(3)之間添加了一行代碼disposable.dispose(),我們來看下輸出結(jié)果:
可以看到observer沒有收到observable發(fā)送的onNext(3)和onComplete事件,原因在于observable在發(fā)送完emitter.onNext(2)后調(diào)用了disposable.dispose(),由此可以看出這個disposable應(yīng)該就是用于中斷事件訂閱的,這個disposable則是在observer調(diào)用onSubscribe(Disposable d) 方法時獲取的。
這個disposable.dispose()執(zhí)行了哪些操作呢?我們點(diǎn)進(jìn)去看下:
public interface Disposable {
/**
* Dispose the resource, the operation should be idempotent.
*/
void dispose();
/**
* Returns true if this resource has been disposed.
* @return true if this resource has been disposed
*/
boolean isDisposed();
}
可以看到這是一個接口方法,其中dispose()方法就是用來中斷事件訂閱流程的;isDisposed()方法則是判斷當(dāng)前事件訂閱是否被中斷,具體的實現(xiàn)細(xì)節(jié)在其實現(xiàn)類中。不知道大家還有沒有印象,在上一節(jié)中我們提到一個關(guān)鍵類ObservableCreate類,我們再看一下這個類的相關(guān)代碼:
在上一篇文章中,我們在分析事件訂閱流程時提到過,在source.subscribe(parent);代碼執(zhí)行之前會先執(zhí)行observer.onSubscribe(parent);代碼。也就是obsever的4個方法中,onSubscribe方法最先被執(zhí)行,而這個parent就是我們前面獲取的Disposable接口對象,也就是CreateEmitter,我們可以看到這個類繼承了Disposable接口,因此當(dāng)我們調(diào)用disposable.dispose()方法時,實際上執(zhí)行的是CreateEmitter類中的實現(xiàn)方法,isDisposed()方法同理。那我們就來看下CreateEmitter類中這兩個實現(xiàn)方法:
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
可以看到,它是委托給了DisposableHelper這個類來完成的,這個DisposableHelper又是什么東西?我們點(diǎn)進(jìn)去看下:
public enum DisposableHelper implements Disposable {
/**
* The singleton instance representing a terminal, disposed state, don't leak it.
*/
DISPOSED
;
/**
* Checks if the given Disposable is the common {@link #DISPOSED} enum value.
* @param d the disposable to check
* @return true if d is {@link #DISPOSED}
*/
public static boolean isDisposed(Disposable d) {
return d == DISPOSED;
}
//.......代碼省略
/**
* Atomically disposes the Disposable in the field if not already disposed.
* @param field the target field
* @return true if the current thread managed to dispose the Disposable
*/
public static boolean dispose(AtomicReference<Disposable> field) {
//......代碼省略
}
//......代碼省略
}
可以看到這個類是一個枚舉類,它有一個枚舉常量DISPOSED,這是一個事件訂閱中斷標(biāo)識,在isDisposed(Disposable d)方法中,就是判斷傳入的參數(shù)對象(Disposable)是否等于該標(biāo)識位從而判斷該對象的訂閱是否被中斷。
我們要重點(diǎn)分析的是這個dispose(AtomicReference<Disposable> field)方法,這個方法接收一個AtomicReference類型的參數(shù),這是因為CreateEmitter繼承了AtomicReference類,這樣保證了操作的原子性,防止在多線程當(dāng)中出現(xiàn)數(shù)據(jù)錯誤。我們來仔細(xì)分析下這個方法:
public static boolean dispose(AtomicReference<Disposable> field) {
//1、獲取當(dāng)前傳遞進(jìn)來的對象所持有的disposable對象
Disposable current = field.get();
//2、終止標(biāo)識
Disposable d = DISPOSED;
//3、當(dāng)前current不等于終止標(biāo)識(dispose()方法還未被調(diào)用)
if (current != d) {
//4、使用AtomicReference的原子方法將終止標(biāo)識設(shè)置到field對象中,并返回field對象中的舊值
//并將其保存在current中
current = field.getAndSet(d);
//5、current仍舊不等于終止標(biāo)識
//備注:當(dāng)?shù)谝淮握{(diào)用dispose()方法時,此時current為空,滿足這個條件,下面的current != null為false,直接返回true;
//另外一種情況就是程序多次調(diào)用了dispose()方法,但是disposable值不等于終止標(biāo)識,說明之前的設(shè)置失敗了,
//此時current不為空,再次調(diào)用dispose()方法
if (current != d) {
if (current != null) {
current.dispose();
}
//7、返回true,表示當(dāng)前線程成功的設(shè)置了終止標(biāo)識
return true;
}
}
//8、之前已經(jīng)調(diào)用過dispose()方法,并且已經(jīng)正確設(shè)置了disposable終止標(biāo)識,
//訂閱事件已經(jīng)被終止了,再次調(diào)用該方法時直接返回false,表示設(shè)置終止標(biāo)識失敗
return false;
}
從上面的代碼分析中可以看出,dispose()方法中斷訂閱的方式只是向AtomicReference<Disposable>這個泛型類中設(shè)置了一個終止標(biāo)識,那么這個終止標(biāo)識是如何影響到onNext,onComplete等方法的呢?讓我們回過頭來再看下CreateEmitter中的onNext等方法:
@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()) {
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 {
observer.onError(t);
} finally {
dispose();
}
return true;
}
return false;
}
@Override
public void onComplete() {
if (!isDisposed()) {
try {
observer.onComplete();
} finally {
dispose();
}
}
}
我們來看onNext方法,它先判斷要發(fā)射的數(shù)據(jù)是否為空,為空就拋出異常。接著在if語句中判斷isDisposed()返回值,如果isDisposed()返回false,表示訂閱已經(jīng)被終止,隨后的observer.onNext(t)也就不會被執(zhí)行。
隨后的onComplete和onError都是通過判斷isDisposed()的返回值來決定是否執(zhí)行接下來的操作(即observer.onComplete和observer.onError),而且我們發(fā)現(xiàn)observer中的onComplete和onError之間是互斥的,也就是說這兩個方法只有一個會執(zhí)行,如果先執(zhí)行了onComplete,onError就不會執(zhí)行;反之先執(zhí)行onError,onComplete就不會執(zhí)行。我們通過分析源碼發(fā)現(xiàn)不管是先執(zhí)行onError還是先執(zhí)行onComplete,只要當(dāng)前訂閱事件還未被終止,他們最終都會調(diào)用dispose()方法來終止訂閱事件,最終會導(dǎo)致isDisposed()返回為false,自然也就不會再執(zhí)行另外一個了。
到此為止,整個的事件訂閱取消流程就分析完了,我們來總結(jié)下:
- 1、在事件訂閱開始時,最先執(zhí)行的是observer中的onSubscribe(Disposable d)方法,也就是ObservableCreate類中subscribeActual(Observer<? super T> observer)方法里面的observer.onSubscribe(parent)這個方法,我們獲取到的disposable實際上就是這個parent,也就是包裝了外部傳進(jìn)來的observer觀察者的CreateEmitter類(該類繼承了Disposable接口)
- 2、調(diào)用disposable.dispose()方法終止事件訂閱流程,實際上調(diào)用的是Disposable的實現(xiàn)類CreateEmitter中的實現(xiàn)方法
- 3、在CreateEmitter的dispose()實現(xiàn)方法中,委托DisposableHelper類實現(xiàn)具體的取消訂閱流程;isDisposed()方法也是如此
- 4、DisposableHelper類是一個枚舉類,它也實現(xiàn)了Disposable接口,內(nèi)部有一個枚舉常量DISPOSED,這是一個標(biāo)識位。在dispose()方法中,給傳入的CreateEmitter設(shè)置該標(biāo)識位,而CreateEmitter當(dāng)中的onNext,onComplete以及onError方法均需要根據(jù)isDisposed()的返回值來決定接下來的操作是否執(zhí)行;而isDisposed()方法正是根據(jù)傳入對象所持有的標(biāo)識位是否等于DISPOSED終止標(biāo)識來決定其返回true還是false。至此,中斷標(biāo)識位就是通過這樣的方式來影響事件中的訂閱相關(guān)方法(即CreateEmitter中的onNext,onComplete以及onError方法),進(jìn)而影響到外部觀察者對象(observer)中對應(yīng)的事件接收方法。
在下一章RxJava2筆記(三、訂閱線程切換)中,我們將接著分析訂閱線程切換時如何進(jìn)行的。