一篇部落格讓你瞭解RxJava

yangxi_001發表於2017-07-20

轉自:http://blog.csdn.net/u012124438/article/details/53730717

RxJava可以說是2016年最流行的專案之一了,最近也接觸了一下RxJava,於是想寫一篇部落格,希望能通過這篇部落格讓大家能對其進行了解,本篇部落格是基於RxJava2.0,跟RxJava1.0還是有很多不同的

基礎知識

RxJava的核心就是“非同步”兩個字,其最關鍵的東西就是兩個:

  1. Observable(被觀察者)

  2. Observer/Subscriber(觀察者)

Observable可以發出一系列的 事件,這裡的事件可以是任何東西,例如網路請求、複雜計算處理、資料庫操作、檔案操作等等,事件執行結束後交給 Observer回撥處理。

Observable可以理解為事件的傳送者,就好像快遞的寄出者,而這些事件就好比快遞 
Observer可以理解為事件的接收者,就好像快遞的接收者

那他們之間是如何進行聯絡的呢?答案就是通過subscribe()方法,下面的程式碼就是RXJAVA中Observable與Observer進行關聯的典型方式:

//建立一個被觀察者 Observable
    Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> e) throws Exception {
            e.onNext(5);
            e.onNext(6);
            e.onNext(7);
            e.onNext(8);
            e.onComplete();
        }
    });

    //建立觀察者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.toString());
        }

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

        @Override
        public void onComplete() {
            Log.d(TAG, "complete");
        }
    };
    //建立關聯
    observable.subscribe(observer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

執行專案,我們可以看到,數字已經列印出來 
這裡寫圖片描述

這裡需要強調的是: 只有當觀察者和被觀察者建立連線之後, 被觀察者才會開始傳送事件. 也就是呼叫了subscribe()方法之後才開始傳送事件.

上面我們看到觀察者和被觀察者的邏輯是分開寫的,那能不能合在一起寫呢?答案是肯定的,這也是RxJava比較突出的優點,那就是鏈式操作,程式碼如下:

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> e) throws Exception {
        e.onNext(5);
        e.onNext(6);
        e.onNext(7);
        e.onNext(8);
        e.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.toString());
    }

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

    @Override
    public void onComplete() {
        Log.d(TAG, "complete");
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

有時候,你可能覺得,我就列印幾個數,還要把Observable寫的那麼麻煩,能不能簡便一點呢?答案是肯定的,RxJava內建了很多簡化建立Observable物件的函式,比如Observable.just就是用來建立只發出一個事件就結束的Observable物件,上面建立Observable物件的程式碼可以簡化為一行

Observable<String> observable = Observable.just("hello");
  • 1
  • 1

同樣對於Observer,這個例子中,我們其實並不關心OnComplete和OnError,我們只需要在onNext的時候做一些處理,這時候就可以使用Consumer類。

Observable<String> observable = Observable.just("hello");
   Consumer<String> consumer = new Consumer<String>() {
       @Override
       public void accept(String s) throws Exception {
           System.out.println(s);
       }
   };
    observable.subscribe(consumer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

這裡寫圖片描述

其實在RxJava中,我們可以為 Observer中的三種狀態根據自身需要分別建立一個回撥動作,通過Action 來替代onComplete():,通過Consumer來替代 onError(Throwable t)和onNext(T t)

Observable<String> observable = Observable.just("hello");
    Action onCompleteAction = new Action() {
        @Override
        public void run() throws Exception {
            Log.i(TAG, "complete");
        }
    };
    Consumer<String> onNextConsumer = new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.i(TAG, s);
        }
    };
    Consumer<Throwable> onErrorConsumer = new Consumer<Throwable>() {
        @Override
        public void accept(Throwable throwable) throws Exception {
            Log.i(TAG, "error");
        }
    };
    observable.subscribe(onNextConsumer, onErrorConsumer, onCompleteAction);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

這裡寫圖片描述

Observable.just同樣可以傳送多個引數

Observable observable = Observable.just("you", "are", "beautiful");
Consumer<String> onNextConsumer = new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.i(TAG, s);
    }
};
observable.subscribe(onNextConsumer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這裡寫圖片描述

例子:來一個簡單的例子來了解事件的產生到消費、訂閱的過程:從res/mipmap中取出一張圖片,顯示在ImageView上。

final ImageView ivLogo = (ImageView) findViewById(R.id.logo);
Observable.create(new ObservableOnSubscribe<Drawable>() {


    @Override
    public void subscribe(ObservableEmitter<Drawable> e) throws Exception {
        // 從mipmap取出一張圖片作為Drawable物件
        Drawable drawable = ContextCompat.getDrawable(MainActivity.this, R.mipmap.ic_launcher);

        // 把Drawable物件傳送出去
        e.onNext(drawable);
        e.onComplete();
    }
}).subscribe(new Observer<Drawable>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Drawable value) {
        ivLogo.setImageDrawable(value);
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

這樣就完成了一個簡單的圖片的設定 
這裡寫圖片描述

ObservableEmitter和Disposable

ObservableEmitter: ObservableEmitter可以理解為發射器,這個就是用來發出事件的,它可以發出三種型別的事件,通過呼叫emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分別發出next事件、complete事件和error事件。 
注意:但是事件的傳送是有一定的規定的,就好比寄快遞也要有一定要求,不是什麼都能寄的:

1.被觀察者可以傳送無限個onNext, 觀察者也可以接收無限個onNext. 
2.當Observable傳送了一個onComplete後, Observable的onComplete之後的事件將會繼續傳送, 而Observer收到onComplete事件之後將不再繼續接收事件. 
3.當Observable傳送了一個onError後, Observable中onError之後的事件將繼續傳送, 而Observer收到onError事件之後將不再繼續接收事件. 
4.Observable可以不傳送onComplete或onError. 
5.最為關鍵的是onComplete和onError必須唯一併且互斥, 即不能發多個onComplete, 也不能發多個onError, 也不能先發一個onComplete, 然後再發一個onError, 反之亦然

注: 關於onComplete和onError唯一併且互斥這一點, 是需要自行在程式碼中進行控制, 如果你的程式碼邏輯中違背了這個規則, 並不一定會導致程式崩潰. 比如傳送多個onComplete是可以正常執行的, 依然是收到第一個onComplete就不再接收了, 但若是傳送多個onError, 則收到第二個onError事件會導致程式會崩潰.當我們寫多個onComplete時,不會報錯

當我們又有onComplete又有onError時,發現在呼叫onComplete後會爆出異常

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> e) throws Exception {
        e.onNext(5);
        e.onNext(6);
        e.onNext(7);
        e.onNext(8);

        e.onError(new NullPointerException());
        e.onComplete();
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

這是onComplete在onError前呼叫的情況 
這裡寫圖片描述

當我們寫兩個onError時,會先接受前面的所有事件,最後才報錯 
這裡寫圖片描述

介紹了ObservableEmitter, 接下來介紹Disposable, 當呼叫dispose()方法時, 它就會將觀察者和被觀察者的聯絡切斷, 從而導致觀察者收不到事件.

注意: 呼叫dispose()並不會導致Observable不再繼續傳送事件, Observable會繼續傳送剩餘的事件. 
看一下下面這個例子:

Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "emitter 1");
            emitter.onNext(1);
            Log.d(TAG, "emitter 2");
            emitter.onNext(2);
            Log.d(TAG, "emitter 3");
            emitter.onNext(3);
            Log.d(TAG, "emitter complete");
            emitter.onComplete();
            Log.d(TAG, "emitter 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");
        }
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

列印如下: 
這裡寫圖片描述

在收到onNext 2這個事件後, 我們中斷了聯絡, 但是Observable 
仍然傳送了3, complete, 4這幾個事件, 而且Observable 
並沒有因為傳送了onComplete而停止. 同時可以看到Observer的onSubscribe()方法是最先呼叫的.

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) {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

不帶任何引數的subscribe() 表示Observer不關心任何事件,Observable傳送什麼資料都隨你 
帶有一個Consumer引數的方法表示Observer只關心onNext事件, 其他的事件我假裝沒看見, 因此我們如果只需要onNext事件可以這麼寫:

Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "emitter 1");
            emitter.onNext(1);
            Log.d(TAG, "emitter 2");
            emitter.onNext(2);
            Log.d(TAG, "emitter 3");
            emitter.onNext(3);
            Log.d(TAG, "emitter complete");
            emitter.onComplete();
            Log.d(TAG, "emitter 4");
            emitter.onNext(4);
        }
    }).subscribe(new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.d(TAG, "onNext: " + integer);
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

其他方式也是類似的方式

執行緒排程

正常情況下, Observer和Observable是工作在同一個執行緒中的, 也就是說Observable在哪個執行緒發事件, Observer就在哪個執行緒接收事件. 
RxJava中, 當我們在主執行緒中去建立一個Observable來傳送事件, 則這個Observable預設就在主執行緒傳送事件. 
當我們在主執行緒去建立一個Observer來接收事件, 則這個Observer預設就在主執行緒中接收事件,但其實在現實工作中我們更多的是需要進行執行緒切換的,最常見的例子就是在子執行緒中請求網路資料,在主執行緒中進行展示

要達到這個目的, 我們需要先改變Observable傳送事件的執行緒, 讓它去子執行緒中傳送事件, 然後再改變Observer的執行緒, 讓它去主執行緒接收事件. 通過RxJava內建的執行緒排程器可以很輕鬆的做到這一點. 接下來看一段程式碼:

Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());
            Log.d(TAG, "emitter 1");
            emitter.onNext(1);
        }
    });

    Consumer<Integer> consumer = new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());
            Log.d(TAG, "onNext: " + integer);
        }
    };

    observable.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(consumer);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這裡寫圖片描述 
可以看到, observable傳送事件的執行緒的確改變了, 是在一個叫 RxNewThreadScheduler-1的執行緒中傳送的事件, 而consumer 仍然在主執行緒中接收事件, 這說明我們的目的達成了, 接下來看看是如何做到的.

這段程式碼只不過是增加了兩行程式碼:

.subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
  • 1
  • 2
  • 1
  • 2

簡單的來說, subscribeOn() 指定的是Observable傳送事件的執行緒, observeOn() 指定的是Observer接收事件的執行緒. 
多次指定Observable的執行緒只有第一次指定的有效, 也就是說多次呼叫subscribeOn() 只有第一次的有效, 其餘的會被忽略. 
多次指定Observer的執行緒是可以的, 也就是說每呼叫一次observeOn() , Observer的執行緒就會切換一次.例如:

observable.subscribeOn(Schedulers.newThread())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.io())
        .subscribe(consumer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

這段程式碼中指定了兩次上游傳送事件的執行緒, 分別是newThread和IO執行緒, 下游也指定了兩次執行緒,分別是main和IO執行緒. 執行結果為: 
這裡寫圖片描述

可以看到, Observable雖然指定了兩次執行緒, 但只有第一次指定的有效, 依然是在RxNewThreadScheduler執行緒中, 而Observer則跑到了RxCachedThreadScheduler 中, 這個CacheThread其實就是IO執行緒池中的一個.

在 RxJava 中,提供了一個名為 Scheduler 的執行緒排程器,RxJava 內部提供了4個排程器,分別是:

Schedulers.io(): I/O 操作(讀寫檔案、資料庫、網路請求等),與newThread()差不多,區別在於io() 的內部實現是是用一個無數量上限的執行緒池,可以重用空閒的執行緒,因此多數情況下 io() 效率比 newThread() 更高。值得注意的是,在 io() 下,不要進行大量的計算,以免產生不必要的執行緒;

Schedulers.newThread(): 開啟新執行緒操作;

Schedulers.immediate(): 預設指定的執行緒,也就是當前執行緒;

Schedulers.computation():計算所使用的排程器。這個計算指的是 CPU 密集型計算,即不會被 I/O等操作限制效能的操作,例如圖形的計算。這個 Scheduler 使用的固定的執行緒池,大小為 CPU 核數。值得注意的是,不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU;

AndroidSchedulers.mainThread(): RxJava 擴充套件的 Android 主執行緒;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這些內建的Scheduler已經足夠滿足我們開發的需求, 因此我們應該使用內建的這些選項, 在RxJava內部使用的是執行緒池來維護這些執行緒, 所有效率也比較高.

例子:還是用之前設定圖片的例子,這次我們在子執行緒中進行網路請求獲取圖片,在主執行緒中對圖片進行設定

final ImageView ivLogo = (ImageView) findViewById(R.id.logo);
Observable.create(new ObservableOnSubscribe<Drawable>() {


    @Override
    public void subscribe(ObservableEmitter<Drawable> e) throws Exception {
        try {
            Drawable drawable = Drawable.createFromStream(new URL("https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2502144641,437990411&fm=80&w=179&h=119&img.JPEG").openStream(), "src");
            e.onNext(drawable);
        } catch (IOException error) {
            e.onError(error);
        }
    }
})// 指定 subscribe() 所在的執行緒,也就是上面subscribe()方法呼叫的執行緒
        .subscribeOn(Schedulers.io())
        // 指定 Observer 回撥方法所在的執行緒,也就是onCompleted, onError, onNext回撥的執行緒
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Drawable>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Drawable value) {
        ivLogo.setImageDrawable(value);
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

這段程式碼就做一件事,在 io 執行緒載入一張網路圖片,載入完畢之後在主執行緒中顯示到ImageView上。

操作符的使用

在瞭解基本知識和執行緒排程後,我們來學習一下RxJava各種神奇的操作符

Map 
Map是RxJava中最簡單的一個變換操作符了, 它的作用就是對Observable傳送的每一個事件應用一個函式, 使得每一個事件都按照指定的函式去變化.

Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }
    }).map(new Function<Integer, String>() {
        @Override
        public String apply(Integer integer) throws Exception {
            return "This is result " + integer;
        }
    }).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.d(TAG, s);
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在Observable我們傳送的是數字型別, 而在Observer我們接收的是String型別, 中間起轉換作用的就是Map操作符, 執行結果為: 
這裡寫圖片描述

通過Map, 可以將Observable發來的事件轉換為任意的型別, 可以是一個Object, 也可以是一個集合,功能非常強大

例子:還是以圖片載入的例子,我們傳進來一個圖片的路徑,然後通過Map進行轉換成drawble再傳送給觀察者

final ImageView ivLogo = (ImageView) findViewById(R.id.logo);
Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        e.onNext("https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=4db5130a073b5bb5a1d727fe06d2d523/cf1b9d16fdfaaf51965f931e885494eef11f7ad6.jpg");
    }
}).map(new Function<String, Drawable>() {
    @Override
    public Drawable apply(String url) throws Exception {
        try {
            Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "src");
            return drawable;
        } catch (IOException e) {

        }
        return null;
    }
})  .subscribeOn(Schedulers.io())
        // 指定 Observer 回撥方法所在的執行緒,也就是onCompleted, onError, onNext回撥的執行緒
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Drawable>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(Drawable value) {
                if (value != null) {
                    ivLogo.setImageDrawable(value);
                }
            }

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

            @Override
            public void onComplete() {

            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

效果如下: 
這裡寫圖片描述

經過改寫程式碼後,有什麼變化呢? Observable 建立了一個 String 事件,也就是產生一個url,通過 map 操作符進行變換,返回Drawable物件,這個變換指的就是通過url進行網路圖片請求,返回一個Drawable。所以簡單的來說就是把String事件,轉換為Drawable事件。邏輯表示就是 
Observable –> map變換 –> Observable

FlatMap 
FlatMap將一個傳送事件的Observable變換為多個傳送事件的Observables,然後將它們發射的事件合併後放進一個單獨的Observable裡.

Observable每傳送一個事件, flatMap都將對其進行轉換, 然後傳送轉換之後的新的事件, Observer接收到的就是轉換後傳送的資料. 這裡需要注意的是, flatMap並不保證事件的順序, 如果需要保證順序則需要使用concatMap.

 Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }
    }).flatMap(new Function<Integer, ObservableSource<String>>() {
        @Override
        public ObservableSource<String> apply(Integer integer) throws Exception {
            final List<String> list = new ArrayList<>();
            for (int i = 0; i < 3; i++) {
                list.add("I am value " + integer);
            }
            return Observable.fromIterable(list).delay(10, TimeUnit.MILLISECONDS);
        }
    }).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.d(TAG, s);
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

效果如下: 
這裡寫圖片描述

Map 與 flatMap 這兩個操作符的共同點在於,他們都是把一個物件轉換為另一個物件,但須注意以下這些特點:

1.flatMap 返回的是一個Observable物件,而 map 返回的是一個普通轉換後的物件; 
2.flatMap 返回的Observable物件並不是直接傳送到Subscriber的回撥中,而是重新建立一個Observable物件,並啟用這個Observable物件,使之開始傳送事件;而 map 變換後返回的物件直接發到Subscriber回撥中; 
3.flatMap 變換後產生的每一個Observable物件傳送的事件,最後都匯入同一個Observable,進而傳送給Subscriber回撥; 
4.map返回型別 與 flatMap 返回的Observable事件型別,可以與原來的事件型別一樣; 
5.可以對一個Observable多次使用 map 和 flatMap;

鑑於 flatMap 自身強大的功能,這常常被用於 巢狀的非同步操作,例如巢狀網路請求。傳統的巢狀請求,一般都是在前一個請求的 onSuccess() 回撥裡面發起新的請求,這樣一旦巢狀多個的話,縮排就是大問題了,而且嚴重的影響程式碼的可讀性。而RxJava巢狀網路請求仍然通過鏈式結構,保持程式碼邏輯的清晰!舉個栗子:

public interface Api {
    @GET
    Observable<LoginResponse> login(@Body LoginRequest request);

    @GET
    Observable<RegisterResponse> register(@Body RegisterRequest request);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

接著建立一個Retrofit客戶端:

private static Retrofit create() {
    OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
    builder.readTimeout(10, TimeUnit.SECONDS);
    builder.connectTimeout(9, TimeUnit.SECONDS);

    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
    }

    return new Retrofit.Builder().baseUrl(ENDPOINT)
            .client(builder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

發起請求就很簡單了:

Api api = retrofit.create(Api.class);
api.login(request)
        .subscribeOn(Schedulers.io())               //在IO執行緒進行網路請求
        .observeOn(AndroidSchedulers.mainThread())  //回到主執行緒去處理請求結果
        .subscribe(new Observer<LoginResponse>() {
            @Override
            public void onSubscribe(Disposable d) {}

            @Override
            public void onNext(LoginResponse value) {}

            @Override
            public void onError(Throwable e) {
                Toast.makeText(mContext, "登入失敗", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onComplete() {
                Toast.makeText(mContext, "登入成功", Toast.LENGTH_SHORT).show();
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

concatMap 
這裡也簡單說一下concatMap吧, 它和flatMap的作用幾乎一模一樣, 只是它的結果是嚴格按照上游傳送的順序來傳送的, 來看個程式碼吧:

Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }
    }).concatMap(new Function<Integer, ObservableSource<String>>() {
        @Override
        public ObservableSource<String> apply(Integer integer) throws Exception {
            final List<String> list = new ArrayList<>();
            for (int i = 0; i < 3; i++) {
                list.add("I am value " + integer);
            }
            return Observable.fromIterable(list).delay(10,TimeUnit.MILLISECONDS);
        }
    }).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.d(TAG, s);
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

只是將之前的flatMap改為了concatMap, 其餘原封不動, 執行結果如下: 
這裡寫圖片描述

可以看到, 結果仍然是有序的.

ZIP 
Zip通過一個函式將多個Observable傳送的事件結合到一起,然後傳送這些組合到一起的事件. 它按照嚴格的順序應用這個函式。它只發射與發射資料項最少的那個Observable一樣多的資料。

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

    Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            Log.d(TAG, "emitter A");
            emitter.onNext("A");
            Log.d(TAG, "emitter B");
            emitter.onNext("B");
            Log.d(TAG, "emitter C");
            emitter.onNext("C");
            Log.d(TAG, "emitter complete2");
            emitter.onComplete();
        }
    });

    Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
        @Override
        public String apply(Integer integer, String s) throws Exception {
            return integer + s;
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "onSubscribe");
        }

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

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

        @Override
        public void onComplete() {
            Log.d(TAG, "onComplete");
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

我們分別建立了observable, 一個傳送1,2,3,4,Complete, 另一個傳送A,B,C,Complete, 接著用Zip把發出的事件組合, 來看看執行結果吧: 
這裡寫圖片描述 
觀察發現observable1傳送事件後,observable2才傳送 
這是因為我們兩個observable都是執行在同一個執行緒裡, 同一個執行緒裡執行程式碼肯定有先後順序呀.

Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "emit 1");
            emitter.onNext(1);
            Thread.sleep(1000);

            Log.d(TAG, "emit 2");
            emitter.onNext(2);
            Thread.sleep(1000);

            Log.d(TAG, "emit 3");
            emitter.onNext(3);
            Thread.sleep(1000);

            Log.d(TAG, "emit 4");
            emitter.onNext(4);
            Thread.sleep(1000);

            Log.d(TAG, "emit complete1");
            emitter.onComplete();
        }
    }).subscribeOn(Schedulers.io());

    Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            Log.d(TAG, "emit A");
            emitter.onNext("A");
            Thread.sleep(1000);

            Log.d(TAG, "emit B");
            emitter.onNext("B");
            Thread.sleep(1000);

            Log.d(TAG, "emit C");
            emitter.onNext("C");
            Thread.sleep(1000);

            Log.d(TAG, "emit complete2");
            emitter.onComplete();
        }
    }).subscribeOn(Schedulers.io());

    Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
        @Override
        public String apply(Integer integer, String s) throws Exception {
            return integer + s;
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "onSubscribe");
        }

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

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

        @Override
        public void onComplete() {
            Log.d(TAG, "onComplete");
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

好了, 這次我們讓事件都在IO執行緒裡傳送事件, 再來看看執行結果: 
這裡寫圖片描述

第一個observable明明傳送了四個資料+一個Complete, 之前明明還有的, 為啥到這裡沒了呢? 
這是因為我們之前說了, zip傳送的事件數量跟observable中傳送事件最少的那一個的事件數量是有關的, 在這個例子裡我們observable2只傳送了三個事件然後就傳送了Complete, 這個時候儘管observable1還有事件4 和事件Complete 沒有傳送, 但是它們發不傳送還有什麼意義呢?

from

在RxJava的from操作符到2.0已經被拆分成了3個,fromArray, fromIterable, fromFuture接收一個集合作為輸入,然後每次輸出一個元素給subscriber。

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5}).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.i(TAG, "number:" + integer);
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這裡寫圖片描述

注意:如果from()裡面執行了耗時操作,即使使用了subscribeOn(Schedulers.io()),仍然是在主執行緒執行,可能會造成介面卡頓甚至崩潰,所以耗時操作還是使用Observable.create(…);

filter 
條件過濾,去除不符合某些條件的事件。舉個栗子:

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5})
       .filter(new Predicate<Integer>() {
           @Override
           public boolean test(Integer integer) throws Exception {
               // 偶數返回true,則表示剔除奇數,留下偶數
               return integer % 2 == 0;

           }
       }).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.i(TAG, "number:" + integer);
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

這裡寫圖片描述

take 
最多保留的事件數。

 Observable.just("1", "2", "6", "3", "4", "5").take(2).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

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

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這裡寫圖片描述 
可以發現我們傳送了6個String,最後只列印了前兩個,這就是take過濾掉的結果

doOnNext 
如果你想在處理下一個事件之前做某些事,就可以呼叫該方法

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}).filter(new Predicate<Integer>() {
    @Override
    public boolean test(Integer integer) throws Exception {
        // 偶數返回true,則表示剔除奇數
        return integer % 2 == 0;
    }
})// 最多保留三個,也就是最後剩三個偶數
        .take(3).doOnNext(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        // 在輸出偶數之前輸出它的hashCode
        Log.i(TAG, "hahcode = " + integer.hashCode() + "");
    }
}).subscribe(new Observer<Integer>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

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

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

這裡寫圖片描述

debounce 
debounce也是用於事件的過濾,可以指定過濾事件的時間間隔

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> e) throws Exception {
        int i = 0;
        int[] times = new int[]{100, 1000};
        while (true) {
            i++;
            if (i >= 100)
                break;
            e.onNext(i);
            try {
                // 注意!!!!
                // 當i為奇數時,休眠1000ms,然後才傳送i+1,這時i不會被過濾掉
                // 當i為偶數時,只休眠100ms,便傳送i+1,這時i會被過濾掉
                Thread.sleep(times[i % 2]);
            } catch (InterruptedException error) {
                error.printStackTrace();
            }
        }
        e.onComplete();
    }
})// 間隔400ms以內的事件將被丟棄
        .debounce(400, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Integer>() {


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

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

            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(Integer integer) {
                Log.i(TAG, "integer = " + integer);
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

這裡寫圖片描述

compose 
與 flatMap 類似,都是進行變換,返回Observable物件,啟用併傳送事件。 
1.compose 是唯一一個能夠從資料流中得到原始Observable的操作符,所以,那些需要對整個資料流產生作用的操作(比如,subscribeOn()和observeOn())需要使用 compose 來實現。相較而言,如果在flatMap()中使用subscribeOn()或者observeOn(),那麼它僅僅對在flatMap 中建立的Observable起作用,而不會對剩下的流產生影響。這樣就可以簡化subscribeOn()以及observeOn()的呼叫次數了。 
2.compose 是對 Observable 整體的變換,換句話說, flatMap 轉換Observable裡的每一個事件,而 compose 轉換的是整個Observable資料流。 
3.flatMap 每傳送一個事件都建立一個 Observable,所以效率較低。而 compose 操作符只在主幹資料流上執行操作。 
4.建議使用 compose 代替 flatMap。

First 
只傳送符合條件的第一個事件。可以與contact操作符,做網路快取。 
例子:依次檢查Disk與Network,如果Disk存在快取,則不做網路請求,否則進行網路請求。

// 從快取獲取
        Observable<BookList> fromDisk = Observable.create(new Observable.OnSubscribe<BookList>() {
            @Override
            public void call(Subscriber<? super BookList> subscriber) {
                BookList list = getFromDisk();
                if (list != null) {
                    subscriber.onNext(list);
                } else {
                    subscriber.onCompleted();
                }
            }
        });

// 從網路獲取
        Observable<BookList> fromNetWork = bookApi.getBookDetailDisscussionList();

        Observable.concat(fromDisk, fromNetWork)
                // 如果快取不為null,則不再進行網路請求。反之
                .first()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<BookList>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(BookList discussionList) {

                    }
                });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

Single 
Single與Observable類似,相當於是他的精簡版。訂閱者回撥的不是OnNext/OnError/onCompleted,而是回撥OnSuccess/OnError。

Single.create(new SingleOnSubscribe<Object>() {
    @Override
    public void subscribe(SingleEmitter<Object> e) throws Exception {
        e.onSuccess("hello world");
    }
}).subscribe(new SingleObserver<Object>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onSuccess(Object value) {
        Log.i(TAG, value.toString());
    }

    @Override
    public void onError(Throwable e) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

這裡寫圖片描述

可以配合debounce,避免SearchEditText頻繁請求。

final Subject subject = PublishSubject.create();

subject.debounce(400, TimeUnit.MILLISECONDS)
        .subscribe(new Observer() {


            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }

            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(Object o) {
                // request
            }
        });

edittext.addTextChangedListener(new TextWatcher() {

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        subject.onNext(s.toString());
    }

    @Override
    public void afterTextChanged(Editable s) { }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

RxJava的一些使用場景

場景1: 
取資料,首先檢查記憶體是否有快取 
然後檢查檔案快取中是否有 
最後才從網路中取 
前面任何一個條件滿足,就不會執行後面的

final Observable<String> memory = Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        if (memoryCache != null) {
            emitter.onNext(memoryCache);
        } else {
            emitter.onComplete();
        }
    }
});

final Observable<String> disk  = Observable.create(new ObservableOnSubscribe<String>() {
    String cachePref = getSharedPreferences("rxdeni",MODE_PRIVATE).getString("cache",null);
    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        if (cachePref != null) {
            emitter.onNext(cachePref);
        } else {
            emitter.onComplete();
        }
    }
});

Observable<String> network = Observable.just("network");

//主要就是靠concat operator來實現
Observable.concat(memory, disk, network).firstElement()

        .subscribeOn(Schedulers.newThread())
        .subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println("--------------subscribe: " + s);
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

場景2:介面需要等到多個介面併發取完資料,再更新

Observable<String> observable1 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("haha");
        }
    }).subscribeOn(Schedulers.newThread());

    Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("hehe");
        }
    }).subscribeOn(Schedulers.newThread());


    Observable.merge(observable1, observable2)
            .subscribeOn(Schedulers.newThread())
            .subscribe(new Observer<String>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

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

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

場景3:介面按鈕需要防止連續點選的情況

RxView.clicks(button)
        .throttleFirst(1, TimeUnit.SECONDS)
        .subscribe(new Observer<Object>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {
                Log.i(TAG, "do clicked!");
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

場景4:響應式的介面 
比如勾選了某個checkbox,自動更新對應的preference

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences);

Preference<Boolean> checked = rxPreferences.getBoolean("checked", true);

CheckBox checkBox = (CheckBox) findViewById(R.id.cb_test);
RxCompoundButton.checkedChanges(checkBox)
        .subscribe(checked.asAction());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

場景5:複雜的資料變換

Observable.just("1", "2", "6", "3", "4", "5")
        .map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) throws Exception {
                return Integer.parseInt(s);
            }
        }).filter(new Predicate<Integer>() {
    @Override
    public boolean test(Integer integer) throws Exception {
        return integer.intValue()%2 == 0;
    }
}).distinct().take(2).reduce(new BiFunction<Integer, Integer, Integer>() {
    @Override
    public Integer apply(Integer integer, Integer integer2) throws Exception {
        return integer.intValue() + integer2.intValue();
    }
}).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
       Log.d(TAG,integer.toString());
    }
});

相關文章