RxJava 的基本使用用法(一)

build文件引入依賴

 compile 'io.reactivex.rxjava2:rxjava:2.2.1'
 compile 'io.reactivex.rxjava2:rxandroid:2.1.0'

RxJava 作為一個工具庫,使用的就是通用形式的觀察者模式。

RxJava 的觀察者模式
RxJava 有四個基本概念:Observable (可觀察者,即被觀察者)、 Observer (觀察者)、 subscribe (訂閱)、事件。Observable 和 Observer 通過 subscribe() 方法實現訂閱關系,從而 Observable 可以在需要的時候發出事件來通知 Observer。

與傳統觀察者模式不同, RxJava 的事件回調方法除了普通事件 onNext() (相當于 onClick() / onEvent())之外,還定義了兩個特殊的事件:onCompleted() 和 onError()。

  • onCompleted(): 事件隊列完結。RxJava 不僅把每個事件單獨處理,還會把它們看做一個隊列。RxJava 規定,當不會再有新的 onNext() 發出時,需要觸發 onCompleted() 方法作為標志。

  • onError(): 事件隊列異常。在事件處理過程中出異常時,onError() 會被觸發,同時隊列自動終止,不允許再有事件發出。

  • 在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個,并且是事件序列中的最后一個。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在隊列中調用了其中一個,就不應該再調用另一個。

RxJava 的觀察者模式
基本原理

先假設有兩個通道

上面一根水管為事件產生的水管,叫它上游吧,下面一根水管為事件接收的水管叫它下游吧。

兩根水管通過一定的方式連接起來,使得上游每產生一個事件,下游就能收到該事件。注意這里和官網的事件圖是反過來的, 這里的事件發送的順序是先1,后2,后3這樣的順序, 事件接收的順序也是先1,后2,后3的順序, 我覺得這樣更符合我們普通人的思維, 簡單明了.

這里的上游和下游就分別對應著RxJava中的Observable( 被觀察者)和Observer(觀察者),它們之間的連接就對應著subscribe(),


基本實現

基于以上的概念, RxJava 的基本實現主要有三點:

1、創建 Observer

Observer 即觀察者,它決定事件觸發的時候將有怎樣的行為。 RxJava 中的 Observer 接口的實現方式:

   //創建一個下游  觀察者Observer
    Observer<Integer> observer = new Observer<Integer>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "subscribe");
        }

        @Override
        public void onNext(Integer value) {
            Log.d(TAG, "" + value);
        }

        @Override
        public void onError(Throwable e) {
            Log.d(TAG, "error");
        }

        @Override
        public void onComplete() {
            Log.d(TAG, "complete");
        }
    };

除了 Observer 接口之外,RxJava 還內置了一個實現了 Observer 的抽象類:Subscriber。 Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的:

Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

不僅基本使用方式一樣,實質上,在 RxJava 的 subscribe 過程中,Observer 也總是會先被轉換成一個 Subscriber 再使用。所以如果你只想使用基本功能,選擇 Observer 和 Subscriber 是完全一樣的。

它們的區別對于使用者來說主要有兩點

  • onStart(): 這是 Subscriber 增加的方法。它會在 subscribe 剛開始,而事件還未發送之前被調用,可以用于做一些準備工作,例如數據的清零或重置。這是一個可選方法,默認情況下它的實現為空。需要注意的是,如果對準備工作的線程有要求(例如彈出一個顯示進度的對話框,這必須在主線程執行), onStart() 就不適用了,因為它總是在 subscribe 所發生的線程被調用,而不能指定線程。要在指定的線程來做準備工作,可以使用 doOnSubscribe() 方法,具體可以在后面的文中看到。

  • unsubscribe(): 這是 Subscriber 所實現的另一個接口 Subscription 的方法,用于取消訂閱。在這個方法被調用后,Subscriber 將不再接收事件。一般在這個方法調用前,可以使用 isUnsubscribed() 先判斷一下狀態。 unsubscribe() 這個方法很重要,因為在 subscribe() 之后, Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候盡快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關系,以避免內存泄露的發生。

2、創建 Observable

Observable 即被觀察者,它決定什么時候觸發事件以及觸發怎樣的事件。 RxJava 使用 create() 方法來創建一個 Observable ,并為它定義事件觸發規則:

   //創建一個上游  被觀察者 Observable:
    Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
            emitter.onComplete();
        }
    });
3、Subscribe (訂閱)

創建了 Observable 和 Observer 之后,再用 subscribe() 方法將它們聯結起來,整條鏈子就可以工作了。代碼形式很簡單:

  //建立連接
 observable.subscribe(observer);

這個運行的結果就是:

08-29 17:34:01.648 3853-3853/tongxunlu.com.myapplication W/MainActivity: subscribe
08-29 17:34:01.648 3853-3853/tongxunlu.com.myapplication W/MainActivity: 1
08-29 17:34:01.648 3853-3853/tongxunlu.com.myapplication W/MainActivity: 2
08-29 17:34:01.648 3853-3853/tongxunlu.com.myapplication W/MainActivity: 3
08-29 17:34:01.648 3853-3853/tongxunlu.com.myapplication W/MainActivity: complete

注意: 只有當上游和下游建立連接之后, 上游才會開始發送事件. 也就是調用了subscribe() 方法之后才開始發送事件.

把這段代碼連起來寫就成了RxJava的鏈式操作:

    Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
            emitter.onComplete();
        }
    }).subscribe(new Observer<Integer>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "subscribe");
        }

        @Override
        public void onNext(Integer value) {
            Log.d(TAG, "" + value);
        }

        @Override
        public void onError(Throwable e) {
            Log.d(TAG, "error");
        }

        @Override
        public void onComplete() {
            Log.d(TAG, "complete");
        }
    });

接下來解釋一下其中兩個陌生的玩意:ObservableEmitter和Disposable.

1、ObservableEmitter: Emitter是發射器的意思,那就很好猜了,這個就是用來發出事件的,它可以發出三種類型的事件,通過調用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分別發出next事件、complete事件和error事件

但是,請注意,并不意味著你可以隨意亂七八糟發射事件,需要滿足一定的規則:

  • 上游可以發送無限個onNext, 下游也可以接收無限個onNext.
  • 當上游發送了一個onComplete后, 上游onComplete之后的事件將會繼續發送, 而下游收到onComplete事件之后將不再繼續接收事件.
  • 當上游發送了一個onError后, 上游onError之后的事件將繼續發送, 而下游收到onError事件之后將不再繼續接收事件.
  • 上游可以不發送onComplete或onError.
  • 最為關鍵的是onComplete和onError必須唯一并且互斥, 即不能發多個onComplete, 也不能發多個onError, 也不能先發一個onComplete, 然后再發一個onError, 反之亦然

注: 關于onComplete和onError唯一并且互斥這一點, 是需要自行在代碼中進行控制, 如果你的代碼邏輯中違背了這個規則, **并不一定會導致程序崩潰. ** 比如發送多個onComplete是可以正常運行的, 依然是收到第一個onComplete就不再接收了, 但若是發送多個onError, 則收到第二個onError事件會導致程序會崩潰.

以上幾個規則用示意圖表示如下:

只發送onNext事件
只發送onNext事件
發送onComplete事件
發送onComplete事件
發送onError事件
發送onError事件

2、接下來介紹Disposable, 這個單詞的字面意思是一次性用品,用完即可丟棄的. 那么在RxJava中怎么去理解它呢, 對應于上面的水管的例子, 我們可以把它理解成兩根管道之間的一個機關, 當調用它的dispose()方法時, 它就會將兩根管道切斷, 從而導致下游收不到事件.

注意: 調用dispose()并不會導致上游不再繼續發送事件, 上游會繼續發送剩余的事件.

來看個例子, 我們讓上游依次發送1,2,3,complete,4,在下游收到第二個事件之后, 切斷水管, 看看運行結果:

 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "console--> 1");
                emitter.onNext(1);
                Log.d(TAG, "console--> 2");
                emitter.onNext(2);
                Log.d(TAG, "console--> 3");
                emitter.onNext(3);
                Log.d(TAG, "console--> complete");
                emitter.onComplete();
                Log.d(TAG, "console--> 4");
                emitter.onNext(4);
            }
        }).subscribe(new Observer<Integer>() {
            private Disposable mDisposable;
            private int i;

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

            @Override
            public void onNext(Integer value) {
                Log.d(TAG, "onNext: " + value);
                i++;
                if (i == 2) {
                    Log.d(TAG, "dispose");
                    mDisposable.dispose();
                    Log.d(TAG, "isDisposed : " + mDisposable.isDisposed());
                }
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "error");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "complete");
            }
        });

運行結果為:

08-29 17:51:18.234 4048-4048/? D/MainActivity: subscribe
08-29 17:51:18.234 4048-4048/? D/MainActivity: console--> 1
08-29 17:51:18.235 4048-4048/? D/MainActivity: onNext: 1
08-29 17:51:18.235 4048-4048/? D/MainActivity: console--> 2
08-29 17:51:18.235 4048-4048/? D/MainActivity: onNext: 2
08-29 17:51:18.235 4048-4048/? D/MainActivity: dispose
08-29 17:51:18.235 4048-4048/? D/MainActivity: isDisposed : true
08-29 17:51:18.235 4048-4048/? D/MainActivity: console--> 3
08-29 17:51:18.235 4048-4048/? D/MainActivity: console--> complete
08-29 17:51:18.235 4048-4048/? D/MainActivity: console--> 4

從運行結果我們看到, 在收到onNext 2這個事件后, 切斷了水管, 但是上游仍然發送了3, complete, 4這幾個事件, 但是在下游沒有再接受,next沒有打印3、4。 而且上游并沒有因為發送了onComplete而停止. 同時可以看到下游的onSubscribe()方法是最先調用的.

Disposable的用處不止這些, 后面講解到了線程的調度之后, 我們會發現它的重要性. 隨著后續深入的講解, 我們會在更多的地方發現它的身影.

另外, subscribe()有多個重載的方法:

public final Disposable subscribe() {}
public final Disposable subscribe(Consumer<? super T> onNext) {}
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
public final void subscribe(Observer<? super T> observer) {}

最后一個帶有Observer參數的我們已經使用過了,這里對其他幾個方法進行說明.

  • 不帶任何參數的subscribe() 表示下游不關心任何事件,你上游盡管發你的數據去吧, 下游不管你發什么.
  • 帶有一個Consumer參數的方法表示下游只關心onNext事件, 其他的事件我假裝沒看見, 因此我們如果只需要onNext事件可以這么寫:
  Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "console--> 1");
                emitter.onNext(1);
                Log.d(TAG, "console--> 2");
                emitter.onNext(2);
                Log.d(TAG, "console--> 3");
                emitter.onNext(3);
                Log.d(TAG, "console--> complete");
                emitter.onComplete();
                Log.d(TAG, "console--> 4");
                emitter.onNext(4);
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.d(TAG, "onNext: " + integer);
            }
        });


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容