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

首先我們有必要來了解一下什么是 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 操作符把從一個 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 操作符返回一個 ConnectableObservable 對象并且可以緩存其發射過的數據,這樣即使有訂閱者在其發射數據之后進行訂閱也能收到其之前發射過的數據。不過使用 Replay 操作符我們最好還是限定其緩存的大小,否則緩存的數據太多了可會占用很大的一塊內存。
Replay 操作符能指定緩存的大小或者時間,這樣能避免耗費太多內存。
- Javadoc: replay()
- Javadoc: replay(int)
- Javadoc: replay(long,TimeUnit)
- Javadoc: replay(int,long,TimeUnit)
有一種 replay 返回一個普通的 Observable。它可以接受一個變換函數為參數,這個函數接受原始 Observable 發射的數據項為參數,返回結果 Observable 要發射的一項數據。因此,這個操作符其實是 replay 變換之后的數據項。
- Javadoc: replay(Function)
- Javadoc: replay(Function,int)
- Javadoc: replay(Function,long,TimeUnit)
- Javadoc: replay(Function,int,long,TimeUnit)
示例代碼 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