RxJava 2.x入門新姿勢一

JerryloveEmily發表於2019-03-02

引言

經過幾年的發展,響應式程式設計已經是很流行了,在Android開發中的應用也非常的廣泛,身為Android開發者,則是必須掌握的技術。

正文

網上已經有很多很多RxJava相關的文章,視訊等等教程,但是說實話對於入門,或者新手來說,確實不好理解,上來就是各種,觀察者、被觀察者、訂閱、釋出等等概念,一遍看下來直接就暈了,就感覺RxJava很難,難理解,用的時候也只是依葫蘆畫瓢,暈乎乎的用著,然後就沒有然後了。

這裡我都不說那些概念,因為講概念太抽象,難記住,更難理解。我們用另外一個視角來學習。因為RxJava 1.x的版本 官方已經停止更新了維護了,沒有學習過也沒有關係,RxJava 2.x是全新的,直接學習使用就好了。

首先假設我們在工廠裡上班,工廠都會有流水線,產品經過流水線生產後來訂單了銷售出去。

事件處理模型

這裡假設工廠生產的是一種六邊形的“Jerry帥氣餅乾”,上游是生產車間流水線的事件流,下游是訂單產品的銷售消費事件流。中間連線上下游關係的暫且叫做“Jerry帥氣餅乾生產消費訂單管理系統”(不要臉,名字寫這麼長),為了下文方便抒寫且用“生產訂單管理系統”(PCMS)。以上圖上下游對應的就是Obsersvable被觀察者也是釋出者,下游對應Observer觀察者也是訂閱者。使用RxJava程式碼表示上圖就是:

public void test1() {

        // 上游生成產品流水線
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                Log.d(TAG, "test1 ====== Observable: ------ onNext: Jerry");
                emitter.onNext("Jerry");
                Log.d(TAG, "test1 ====== Observable: ------ onNext: 就是");
                emitter.onNext("就是");
                Log.d(TAG, "test1 ====== Observable: ------ onNext: 帥");
                emitter.onNext("帥");
                Log.d(TAG, "test1 ====== Observable: ------ onNext: !!!");
                emitter.onNext("!!!");
                Log.d(TAG, "test1 ====== Observable: ------ onComplete");
                emitter.onComplete();
                Log.d(TAG, "test1 ====== Observable: ------ onNext: Jerry帥炸天!!!");
                emitter.onNext("Jerry帥炸天!!!");
            }
        });

        // 下游訂單產品銷售
        Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "test1 ====== Observer: onSubscribe");
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "test1 ====== Observer: onNext: " + value);
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "test1 ====== Observer: onError: " + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "test1 ====== Observer: onComplete");
            }
        };

        // 連線上下游的訂單管理系統
        observable.subscribe(observer);
    }
複製程式碼

上述程式碼,上游生產車間流水線就是Observable,下游訂單銷售就是Observer,中間通過“生產訂單管理系統”subscribe來將上下游連線起來。

執行後輸出結果是:

輸出結果

從輸出結果來看,當上遊Observable發出一個生產的餅乾產品事件,下游訂單銷售的Observer就銷售一個餅乾產品事件,而且當上遊呼叫了onComplete方法後,上游的生產事件還是生產餅乾事件(繼續生產了“Jerry帥炸天”餅乾事件),但是下游的訂單銷售卻沒有消費掉。也就是事件產生方呼叫onComplete方法後,之後的事件還會繼續傳送,但是事件接收方就不會接收了。

我們來看看Observable的subscribe方法的引數:ObservableEmitter,Emitter顧名思義是發射器的意思,ObservableEmitter介面繼承自Emitter介面:

public interface Emitter<T> {

    /**
     * Signal a normal value.
     * @param value the value to signal, not null
     */
    void onNext(T value);

    /**
     * Signal a Throwable exception.
     * @param error the Throwable to signal, not null
     */
    void onError(Throwable error);

    /**
     * Signal a completion.
     */
    void onComplete();
}
複製程式碼

介面定義很簡單,就三個方法,onNext我們上門已經用過了,是用來發射傳送事件的,onComplete是用來表示事件傳送完了,後面如果有新的事件傳送,下游接收者可以不用處理,onError方法看註釋說是傳送一個異常事件給下游接收者。到底是不是這樣,我們來試試就曉得了。

public void test2() {

        // 上游生成產品流水線
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                Log.d(TAG, "test2 ====== Observable: ------ onNext: Jerry");
                emitter.onNext("Jerry");
                Log.d(TAG, "test2 ====== Observable: ------ onNext: 就是");
                emitter.onNext("就是");
                Log.d(TAG, "test2 ====== Observable: ------ onNext: 帥");
                emitter.onNext("帥");
                Log.d(TAG, "test2 ====== Observable: ------ onNext: !!!");
                emitter.onNext("!!!");
                Log.d(TAG, "test2 ====== Observable: ------ onError");
                emitter.onError(new IllegalStateException("Jerry餅乾烤焦了,賣出去會被打!"));
                Log.d(TAG, "test2 ====== Observable: ------ onNext: Jerry帥炸天!!!");
                emitter.onNext("Jerry帥炸天!!!");
            }
        });

        // 下游訂單產品銷售
        Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "test2 ====== Observer: onSubscribe");
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "test2 ====== Observer: onNext: " + value);
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "test2 ====== Observer: onError: " + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "test2 ====== Observer: onComplete");
            }
        };

        // 連線上下游的訂單管理系統
        observable.subscribe(observer);
    }
複製程式碼

在上游生產餅乾的時候就生產了一個“Jerry餅乾烤焦了,賣出去會被打!”的錯誤餅乾事件,下游訂單銷售的onError出錯狀態會消費這個事件。而上游在出錯事件後傳送的“Jerry帥炸天!!!”餅乾事件,同樣也只是把事件傳送了處理,下游訂單銷售並沒有接收處理這個事件。

執行後輸出結果:

輸出結果

細心的小夥伴應該會發現,每次執行的時候都會先呼叫下游的onSubscribe方法,這個方法裡有個引數Disposable(用完即可丟棄)意思可以理解成,將上下游的連線切斷,讓上游的生產的餅乾不打包放入下游訂單銷售環節,實際開發中是有這種需求的,當傳送事件出問題的時候就需要斷開事件接收處理。不像最近的疫苗事件,一些不要臉的生物疫苗公司把生產不合格的疫苗上市銷售,傷天害理,謀財害命。下面舉個例子:

public void test3() {

        // 上游生成產品流水線
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                Log.d(TAG, "test3 ====== Observable: ------ onNext: Jerry");
                emitter.onNext("Jerry");
                Log.d(TAG, "test3 ====== Observable: ------ onNext: 就是");
                emitter.onNext("就是");
                Log.d(TAG, "test3 ====== Observable: ------ onNext: 帥");
                emitter.onNext("帥");
                Log.d(TAG, "test3 ====== Observable: ------ onNext: !!!");
                emitter.onNext("!!!");
                Log.d(TAG, "test3 ====== Observable: ------ onComplete");
                emitter.onComplete();
                Log.d(TAG, "test3 ====== Observable: ------ onNext: Jerry帥炸天!!!");
                emitter.onNext("Jerry帥炸天!!!");
            }
        });

        // 下游訂單產品銷售
        Observer<String> observer = new Observer<String>() {

            private Disposable mDisposable;
            private int i;

            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "test3 ====== Observer: onSubscribe");
                mDisposable = d;
            }

            @Override
            public void onNext(String value) {
                Log.d(TAG, "test3 ====== Observer: onNext: " + value);
                i++;
                // 第一個事件接收後,就斷開上下游連線
                if (i == 1) {
                    Log.d(TAG, "test3 ====== Observer: start disposable");
                    mDisposable.dispose();
                    Log.d(TAG, "test3 ====== Observer: isDisposable: " + mDisposable.isDisposed());
                }
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "test3 ====== Observer: onError: " + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "test3 ====== Observer: onComplete");
            }
        };

        // 連線上下游的訂單管理系統
        observable.subscribe(observer);
    }
複製程式碼

這裡我們在下游訂單銷售的onNext方法中,當接收完第一個餅乾事件後,就使用mDisposable.dispose()方法將上下游的連線斷開了,斷開後上遊後續生產的餅乾事件,下游就接收不到。

執行的結果:

image.png

上圖中,也驗證了我們的猜想,當使用dispose斷開上下游連線後,下游就無法再繼續接收事件了。


這一講就先介紹這麼多,這樣的方式理解Observable和Observer以及訂閱動作subscribe是不是容易多了,希望對你有所幫助,下一講使用RxJava來切換變化餅乾事件處理的執行緒(主執行緒、子執行緒)。

相關文章