RxJava2筆記(二、事件取消流程)

在上一篇文章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é)果:


image.png

可以看到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)代碼:


image.png

在上一篇文章中,我們在分析事件訂閱流程時提到過,在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)行的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容