RxJava操作符(09-算術/聚合操作&連接操作)

轉載請標明出處:
http://blog.csdn.net/xmxkf/article/details/51692493
本文出自:【openXu的博客】

目錄:


算術&聚合

1. Count

  Count操作符將一個Observable轉換成一個發射單個值的Observable,這個值表示原始Observable發射的數據的數量。
   如果原始Observable發生錯誤終止,Count不發射數據而是直接傳遞錯誤通知。如果原始Observable永遠不終止,Count既不會發射數據也不會終止。

    這裏寫圖片描述

示例代碼:

Observable.from(new String[] { "one", "two", "three" })
        .count()
        .subscribe(integer->Log.v(TAG, "count:"+integer));

Observable.from(new String[] { "one", "two", "three" })
        .countLong()
        .subscribe(aLong->Log.v(TAG, "countLong:"+aLong));

輸出:

count:3
countLong:3


2. Concat

  concat操作符會依次發射多個Observable的數據,第一個Observable發射的所有數據在第二個Observable發射的任何數據前面,以此類推,直到前面一個Observable終止,Concat纔會訂閱額外的一個Observable。
Merge操作符也差不多,它結合兩個或多個Observable的發射物,但是數據可能交錯,而Concat不會讓多個Observable的發射物交錯。

    這裏寫圖片描述

示例代碼:

//還有一個實例方法叫concatWith,這兩者是等價的:Observable.concat(a,b)和a.concatWith(b)
Observable.concat(
        Observable.interval(100,TimeUnit.MILLISECONDS).take(4),
        Observable.interval(200,TimeUnit.MILLISECONDS).take(5))
        .subscribe(aLong -> Log.v(TAG, "concat:"+aLong));

輸出:

concat:0
concat:1
concat:2
concat:3

concat:0
concat:1
concat:2
concat:3
concat:4


3. Reduce

  Reduce操作符對原始Observable發射數據的第一項應用一個函數,然後再將這個函數的返回值與第二項數據一起傳遞給函數,以此類推,持續這個過程知道原始Observable發射它的最後一項數據並終止,此時Reduce返回的Observable發射這個函數返回的最終值。
  注意如果原始Observable沒有發射任何數據,reduce拋出異常IllegalArgumentException。
  在其它場景中,這種操作有時被稱爲累積,聚集,壓縮,摺疊,注射等。

    這裏寫圖片描述

示例代碼:

Observable.just(1,2,3,4)
        .reduce(new Func2<Integer, Integer, Integer>() {
            //integer爲前面幾項只和,integer2爲當前發射的數據
            @Override
            public Integer call(Integer integer, Integer integer2) {
                Log.v(TAG, "integer:"+integer+"  integer2:"+integer2);
                return integer+integer2;
            }
        }).subscribe(integer -> Log.v(TAG, "reduce:"+integer));

輸出:

integer:1 integer2:2
integer:3 integer2:3
integer:6 integer2:4
reduce:10



連接操作

1. Publish

  Publish 操作符將普通的Observable轉換爲可連接的Observable(ConnectableObservable),ConnectableObservable是Observable的子類。 可連接的Observable (connectable Observable)與普通的Observable差不多,不過它並不會在被訂閱時開始發射數據,而是直到使用了Connect操作符時纔會開始,這樣可以更靈活的控制發射數據的時機。
  注意:如果一個ConnectableObservable已經開始發射數據,再對其進行訂閱只能接受之後發射的數據,訂閱之前已經發射過的數據就丟失了。

    這裏寫圖片描述

示例代碼:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS).take(5);
//使用publish操作符將普通Observable轉換爲可連接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//第一個訂閱者訂閱,不會開始發射數據
connectableObservable.subscribe(new Subscriber<Long>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "1.onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "1.onError");
    }
    @Override
    public void onNext(Long along) {
        Log.v(TAG, "1.onNext:"+along+"->time:"+ sdf.format(new Date()));
    }
});
//開始發射數據
Log.v(TAG, "start time:" + sdf.format(new Date()));
connectableObservable.connect();
//第二個訂閱者延遲2s訂閱,這將導致丟失前面2s內發射的數據
connectableObservable
        .delaySubscription(2, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "2.onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "2.onError");
    }
    @Override
    public void onNext(Long along) {
        Log.v(TAG, "2.onNext:"+along+"->time:"+ sdf.format(new Date()));
    }
});

/*
輸出:
start time:23:01:30
1.onNext:0->time:23:01:31
1.onNext:1->time:23:01:32
2.onNext:1->time:23:01:32
1.onNext:2->time:23:01:33
2.onNext:2->time:23:01:33
1.onNext:3->time:23:01:34
2.onNext:3->time:23:01:34
1.onNext:4->time:23:01:35
2.onNext:4->time:23:01:35
1.onCompleted
2.onCompleted
 */


2. Connect

  connect是ConnectableObservable接口的一個方法,它的作用就是讓ConnectableObservable開始發射數據(即使沒有任何訂閱者訂閱這個Observable,調用connect都會開始發射數據)。
  connect方法返回一個Subscription對象,可以調用它的unsubscribe方法讓Observable停止發射數據給觀察者。

示例代碼:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS);
//使用publish操作符將普通Observable轉換爲可連接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//開始發射數據
Subscription sub = connectableObservable.connect();
//第二個訂閱者延遲2s訂閱,這將導致丟失前面2s內發射的數據
connectableObservable
        .delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                Log.v(TAG, "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.v(TAG, "onError");
            }
            @Override
            public void onNext(Long along) {
                Log.v(TAG, "onNext:"+along+"->time:"+ sdf.format(new Date()));
            }
        });

new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
        //6s之後停止發射數據
        sub.unsubscribe();
    }
},6000);

/*
輸出:
onNext:3->time:23:10:49
onNext:4->time:23:10:50
onNext:5->time:23:10:51
 */


3. RefCount

  RefCount操作符可以看做是Publish的逆向,它能將一個ConnectableObservable對象再重新轉化爲一個普通的Observable對象,如果轉化後有訂閱者對其進行訂閱將會開始發射數據,後面如果有其他訂閱者訂閱,將只能接受後面的數據(這也是轉化之後的Observable 與普通的Observable的一點區別 )。
  還有一個操作符叫share,它的作用等價於對一個Observable同時應用publish和refCount操作。

    這裏寫圖片描述

示例代碼:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS).take(4);
//使用publish操作符將普通Observable轉換爲可連接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//refCount:將ConnectableObservable轉化爲普通Observable
Observable obsRefCount = connectableObservable.refCount();

obs.subscribe(new Subscriber<Long>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "普通obs1:onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "普通obs1:onError");
    }
    @Override
    public void onNext(Long along) {
        Log.v(TAG, "普通obs1:onNext:"+along+"->time:"+ sdf.format(new Date()));
    }
});
obs.delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "普通obs2:onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "普通obs2:onError");
    }
    @Override
    public void onNext(Long along) {
        Log.v(TAG, "普通obs2:onNext:"+along+"->time:"+ sdf.format(new Date()));
    }
});

obsRefCount.subscribe(new Subscriber<Long>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "obsRefCount1:onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "obsRefCount1:onError");
    }
    @Override
    public void onNext(Long along) {
        Log.v(TAG, "obsRefCount1:onNext:"+along+"->time:"+ sdf.format(new Date()));
    }
});
obsRefCount.delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                Log.v(TAG, "obsRefCount2:onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.v(TAG, "obsRefCount2:onError");
            }
            @Override
            public void onNext(Long along) {
                Log.v(TAG, "obsRefCount2:onNext:"+along+"->time:"+ sdf.format(new Date()));
            }
        });

/*
輸出:
普通obs1:onNext:0->time:23:28:28
普通obs1:onNext:1->time:23:28:29
普通obs1:onNext:2->time:23:28:30
普通obs1:onNext:3->time:23:28:31
普通obs1:onCompleted

普通obs2:onNext:0->time:23:28:31
普通obs2:onNext:1->time:23:28:32
普通obs2:onNext:2->time:23:28:33
普通obs2:onNext:3->time:23:28:34
普通obs2:onCompleted

obsRefCount1:onNext:0->time:23:28:28
obsRefCount1:onNext:1->time:23:28:29
obsRefCount1:onNext:2->time:23:28:30
obsRefCount1:onNext:3->time:23:28:31
obsRefCount1:onCompleted

obsRefCount2:onNext:3->time:23:28:31
obsRefCount2:onCompleted
 */


4. Replay

  通過上面的介紹我們瞭解到,ConnectableObservable和普通的Observable最大的區別就是,調用Connect操作符開始發射數據,後面的訂閱者會丟失之前發射過的數據。
  使用Replay操作符返回的ConnectableObservable 會緩存訂閱者訂閱之前已經發射的數據,這樣即使有訂閱者在其發射數據開始之後進行訂閱也能收到之前發射過的數據。Replay操作符能指定緩存的大小或者時間,這樣能避免耗費太多內存。

示例代碼:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Log.v(TAG, "start time:" + sdf.format(new Date()));

//沒有緩存的情況
ConnectableObservable<Long> obs = Observable.interval(1, TimeUnit.SECONDS)
        .take(5)
        .publish();
obs.connect();  //開始發射數據
obs.delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(aLong -> Log.v(TAG, "onNext:"+aLong+"->time:"+ sdf.format(new Date())));


//緩存一個數據
ConnectableObservable<Long> obs1 = Observable.interval(1, TimeUnit.SECONDS)
        .take(5)
        .replay(1);   //緩存1個數據
obs1.connect();  //開始發射數據
obs1.delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(aLong -> Log.v(TAG,
                "1.onNext:"+aLong+"->time:"+ sdf.format(new Date())));

//緩存3s內發射的數據
ConnectableObservable<Long> obs2 = Observable.interval(1, TimeUnit.SECONDS)
        .take(5)
        .replay(3, TimeUnit.SECONDS);   //緩存3s
obs2.connect();  //開始發射數據
obs2.delaySubscription(3, TimeUnit.SECONDS)
        .subscribe(aLong -> Log.v(TAG,
                "2.onNext:"+aLong+"->time:"+ sdf.format(new Date())));

/*
輸出:
start time:14:25:51
onNext:3->time:14:25:55
onNext:4->time:14:25:56

1.onNext:2->time:14:25:54
1.onNext:3->time:14:25:55
1.onNext:4->time:14:25:56

2.onNext:0->time:14:25:54
2.onNext:1->time:14:25:54
2.onNext:2->time:14:25:54
2.onNext:3->time:14:25:55
2.onNext:4->time:14:25:56
 */

從log可以看出,沒有緩存機制的只能收到3.4;緩存1個數據的能收到前面已經發射過的2;緩存3s的將所有已經發射的數據都緩存起來了,所以數據都能收到。緩存的數據在訂閱者訂閱之後立馬發射給訂閱者。


源碼下載:

https://github.com/openXu/RxJavaTest

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章