RxJava2.0 操作符(9)—— Connectable Observable 連接操作符

具有更精確控制訂閱動態的專業觀察器。

Connect
Connect

首先我們有必要來了解一下什么是 Connectable Observable: 就是一種特殊的 Observable 對象,ConnectableObservable 在被訂閱時并不開始發射數據,而是只有在調用 connect 操作符的時候才開始發射數據,所以可以用來更靈活的控制數據發射的時機。

9.1 Public

Publish 操作符將普通的 Observable 轉換為可連接的(ConnectableObservable)。

注意:如果一個 ConnectableObservable 已經開始發射數據,再對其進行訂閱只能接受之后發射的數據,訂閱之前已經發射過的數據就丟失了。

示例代碼:見 9.2

9.2 Connect

指示一個 ConnectableObservable 開始發射數據。

Connect 操作符就是用來觸發 ConnectableObservable 發射數據的。調用 Connect 操作符后會返回一個 Subscription 對象,通過這個 Subscription 對象,我們可以調用其 unsubscribe 方法來終止數據的發射。另外,如果還沒有訂閱者訂閱的時候就應用 Connect 操作符也是可以使其開始發射數據的。

示例代碼:

//使用 publish 操作符創建一個 ConnectableObservable:
ConnectableObservable<Long> connectableObservable = Observable.interval(100,
    TimeUnit.MILLISECONDS).take(6).publish();

// 創建兩個 Consumer 對象
Consumer<Long> consumer1 = new Consumer<Long>(){
    @Override
    public void accept(@NonNull Long aLong) throws Exception {
        Log.e(TAG, "step 1 -> accept:" + aLong);
    }
};

Consumer<Long> consumer2 = new Consumer<Long>(){
    @Override
    public void accept(@NonNull Long aLong) throws Exception {
        Log.e(TAG, "step 2 -> accept:" + aLong);
    }
};

connectableObservable.subscribe(consumer1);
//延遲 300 毫秒訂閱 consumer2
connectableObservable.delay(330, TimeUnit.MILLISECONDS).subscribe(consumer2);
//如果不調用 connect 方法,connectableObservable 則不會發射數據
connectableObservable.connect();

輸出結果:

step 1 -> accept:0
step 1 -> accept:1
step 1 -> accept:2
step 1 -> accept:3
step 2 -> accept:0
step 1 -> accept:4
step 2 -> accept:1
step 1 -> accept:5
step 2 -> accept:2
step 2 -> accept:3
step 2 -> accept:4
step 2 -> accept:5

9.3 RefCount / share

讓一個 ConnectableObservable 行為像普通的 Observable。

RefCount
RefCount

RefCount 操作符把從一個 ConnectableObservable 連接和斷開的過程自動化了。調用 RefCount,返回一個普通的 Observable。當第一個訂閱者訂閱這個 Observable 時,RefCount 連接到下層的可連接 Observable。RefCount 跟蹤有多少個觀察者訂閱它,直到最后一個觀察者完成才斷開與下層可連接 Observable 的連接。

示例代碼:

//使用 publish 操作符創建一個 ConnectableObservable:
ConnectableObservable<Long> connectableObservable = Observable.interval(100, 
    TimeUnit.MILLISECONDS).take(6).publish();

// 創建兩個 Consumer 對象
Consumer<Long> consumer1 = new Consumer<Long>(){
    @Override
    public void accept(@NonNull Long aLong) throws Exception {
        Log.e(TAG, "step 1 -> accept:" + aLong);
    }
};

Consumer<Long> consumer2 = new Consumer<Long>(){
    @Override
    public void accept(@NonNull Long aLong) throws Exception {
        Log.e(TAG, "step 2 -> accept:" + aLong);
    }
};

//這兩種實現方法結果一致
// Observable observable =  Observable.interval(100, TimeUnit.MILLISECONDS).take(6).share();
Observable observable = connectableObservable.refCount();

observable.subscribe(consumer1);
//延遲 300 毫秒訂閱 consumer2
observable.delay(330, TimeUnit.MILLISECONDS).subscribe(consumer2);

輸出結果:

step 1 -> accept:0
step 1 -> accept:1
step 1 -> accept:2
step 1 -> accept:3
step 2 -> accept:0
step 1 -> accept:4
step 2 -> accept:1
step 1 -> accept:5
step 2 -> accept:2
step 2 -> accept:3
step 2 -> accept:4
step 2 -> accept:5

9.3.1 Share

Share 操作符作用與 refCount 相似。內部實現為:

public final Observable<T> share() {
    return publish().refCount();
}

9.4 replay

保證所有的觀察者收到相同的數據序列,即使它們在 Observable 開始發射數據之后才訂閱。

replay
replay

Replay 操作符返回一個 ConnectableObservable 對象并且可以緩存其發射過的數據,這樣即使有訂閱者在其發射數據之后進行訂閱也能收到其之前發射過的數據。不過使用 Replay 操作符我們最好還是限定其緩存的大小,否則緩存的數據太多了可會占用很大的一塊內存。
Replay 操作符能指定緩存的大小或者時間,這樣能避免耗費太多內存。

有一種 replay 返回一個普通的 Observable。它可以接受一個變換函數為參數,這個函數接受原始 Observable 發射的數據項為參數,返回結果 Observable 要發射的一項數據。因此,這個操作符其實是 replay 變換之后的數據項。

示例代碼 1:

Observable<Long> ob1 = Observable.just(1L, 12L);
//緩存兩次,三秒時間內有效。
ConnectableObservable<Long> connectableObservable = ob1.replay(2, 3, TimeUnit.SECONDS);
//ConnectableObservable<Long> connectableObservable = ob1.publish();

Consumer<Long> consumer1 = new Consumer<Long>(){
    @Override
    public void accept(@NonNull Long aLong) throws Exception {
        Log.e(TAG, "accept:" + aLong);
    }
};
Disposable disposable = connectableObservable.subscribe(consumer1);
connectableObservable.connect();

try {
    //間隔一秒取消訂閱,然后重新訂閱,有緩存數據
    Thread.sleep(1000);
    disposable.dispose();
    disposable = connectableObservable.subscribe(consumer1);

    //間隔兩秒取消訂閱后,然后重新訂閱,緩存數據失效
    Thread.sleep(2000);
    disposable.dispose();
    disposable = connectableObservable.subscribe(consumer1);
} catch (InterruptedException e) {
    e.printStackTrace();
}

輸出結果:

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

推薦閱讀更多精彩內容

  • 作者: maplejaw本篇只解析標準包中的操作符。對于擴展包,由于使用率較低,如有需求,請讀者自行查閱文檔。 創...
    maplejaw_閱讀 45,838評論 8 93
  • 本篇文章介主要紹RxJava中操作符是以函數作為基本單位,與響應式編程作為結合使用的,對什么是操作、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,893評論 0 10
  • 注:只包含標準包中的操作符,用于個人學習及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 971評論 0 3
  • RxJava正在Android開發者中變的越來越流行。唯一的問題就是上手不容易,尤其是大部分人之前都是使用命令式編...
    劉啟敏閱讀 1,925評論 1 7
  • 注:只包含標準包中的操作符,用于個人學習及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 2,241評論 2 8