RxJava操作符(05-結合操作)

版權聲明:本文爲openXu原創文章【openXu的博客】,未經博主允許不得以任何形式轉載

目錄:


結合操作就是將多個Observable發射的數據按照一定規則組合後發射出去,接下來看看RxJava中的結合操作符:

1. CombineLatest

  當兩個Observables中的任何一個發射數據時,使用一個函數結合每個Observable發射的最近數據項,並且基於這個函數的結果發射出一個新的數據。
  好比工廠的流水線,下面一件產品需要兩個流水線上的零件組合,流水線1的工人生產了一個零件,只有等流水線2的工人生產了另一個零件的時候,才能組合成一個產品;流水線2的工人速度快一些,很快生產了第二個零件,這時候流水線1的工人還沒有生產第二個零件,流水線2的工人就會拿流水線1的第一個零件將就用着合成第二個產品。這個例子只是方便理解,我們假設零件可以複用。仔細看下圖,應該就能明白這個步驟了:

    這裏寫圖片描述

  CombineLatest操作符能接受2~9個Observable或者一個Observable集合作爲參數,當其中一個Observable要發射數據時,它會用傳入的Func函數對每個Observable最近發射的數據進行組合後發射一個新的數據。這裏有兩個規則:

  • 所有的Observable必須都發射過數據,如果其中一個Observable從來沒發射過數據,將不會組合發射新的數據;
  • 滿足上面條件之後,當其中任何一個Observable要發射數據時,就會調用Func函數對所有Observable最近發射的數據進行組合(每個Observable貢獻一個),然後發射出去。

    這裏寫圖片描述

示例代碼:

//創建不同名稱的Observable(每隔100ms發射一個數據 ):
private Observable<String> getObservable(String name){
    return Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            if(name.contains("-")){
                for (int i = 1; i <=3; i++) {
                    Log.v(TAG, name+i);
                    subscriber.onNext(name+i);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                subscriber.onCompleted();
            }
        }
    }).subscribeOn(Schedulers.newThread());
}

Observable.combineLatest(getObservable("one->"), getObservable("two->"), getObservable("three->"),
        new Func3<String, String, String,String>() {
    //使用一個函數結合它們最近發射的數據,然後發射這個函數的返回值
    @Override
    public String call(String str1, String str2, String str3) {
        return str1+","+str2+","+str3;
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.v(TAG, "combineLatest:"+s);
    }
});

輸出:

one->1
two->1
three->1
combineLatest:one->1,two->1,three->1
one->2
combineLatest:one->2,two->1,three->1
two->2
combineLatest:one->2,two->2,three->1
three->2
combineLatest:one->2,two->2,three->2
one->3
combineLatest:one->3,two->2,three->2
two->3
combineLatest:one->3,two->3,three->2
three->3
combineLatest:one->3,two->3,three->3

從log可以看出,當one和two發射第一條數據的時候,並沒有組合,因爲要等所有的Observable都發射過數據,當three發射第一條數據的時候,Func會組合三個Observable最近發射的數據組合後發射。然後one要發射第二條數據了,Func會拿one的第二條、two的第一條、three的第一條組合;接下來應該是two要發射第二條數據,Func會拿one的第二條,two的第二條,three的第一條組合…

2. Join

  如果一個Observable發射了一條數據,只要在另一個Observable發射的數據定義的時間窗口內,就結合兩個Observable發射的數據,然後發射結合後的數據。

    這裏寫圖片描述

  目標Observable和源Observable發射的數據都有一個有效時間限制,比如目標發射了一條數據(a)有效期爲3s,過了2s後,源發射了一條數據(b),因爲2s<3s,目標的那條數據還在有效期,所以可以組合爲ab;再過2s,源又發射了一條數據(c),這時候一共過去了4s,目標的數據a已經過期,所以不能組合了…

使用join操作符需要4個參數,分別是:

  • 源Observable所要組合的目標Observable
  • 一個函數,接受從源Observable發射來的數據,並返回一個Observable,這個Observable的生命週期決定了源Observable發射出來數據的有效期
  • 一個函數,接受從目標Observable發射來的數據,並返回一個Observable,這個Observable的生命週期決定了目標Observable發射出來數據的有效期
  • 一個函數,接受從源Observable和目標Observable發射來的數據,並返回最終組合完的數據。

Rxjava還實現了groupJoin,基本和join相同,只是最後組合函數的參數不同。
    這裏寫圖片描述

示例代碼:

//目標Observable
Observable<Integer> obs1 = Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for (int i = 1; i < 5; i++) {
            subscriber.onNext(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});
//join
Observable.just("srcObs-")
        .join(obs1,
        //接受從源Observable發射來的數據,並返回一個Observable,
        //這個Observable的生命週期決定了源Observable發射出來數據的有效期
        new Func1<String, Observable<Long>>() {
            @Override
            public Observable<Long> call(String s) {
                return Observable.timer(3000, TimeUnit.MILLISECONDS);
            }
        },
        //接受從目標Observable發射來的數據,並返回一個Observable,
        //這個Observable的生命週期決定了目標Observable發射出來數據的有效期
        new Func1<Integer, Observable<Long>>() {
            @Override
            public Observable<Long> call(Integer integer) {
                return Observable.timer(2000, TimeUnit.MILLISECONDS);
            }
        },
        //接收從源Observable和目標Observable發射來的數據,並返回最終組合完的數據
        new Func2<String,Integer,String>() {
            @Override
            public String call(String str1, Integer integer) {
                return str1 + integer;
            }
        })
.subscribe(new Action1<String>() {
    @Override
    public void call(String o) {
        Log.v(TAG,"join:"+o);
    }
});

//groupJoin
Observable.just("srcObs-").groupJoin(obs1,
        new Func1<String, Observable<Long>>() {
            @Override
            public Observable<Long> call(String s) {
                return Observable.timer(3000, TimeUnit.MILLISECONDS);
            }
        },
        new Func1<Integer, Observable<Long>>() {
            @Override
            public Observable<Long> call(Integer integer) {
                return Observable.timer(2000, TimeUnit.MILLISECONDS);
            }
        },
        new Func2<String,Observable<Integer>, Observable<String>>() {
            @Override
            public Observable<String> call(String s, Observable<Integer> integerObservable) {
                return integerObservable.map(new Func1<Integer, String>() {
                    @Override
                    public String call(Integer integer) {
                        return s+integer;
                    }
                });
            }
        })
        .subscribe(new Action1<Observable<String>>() {
            @Override
            public void call(Observable<String> stringObservable) {
                stringObservable.subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.v(TAG,"groupJoin:"+s);
                    }
                });
            }
        });

輸出:

join:srcObs-1
join:srcObs-2
join:srcObs-3
groupJoin:srcObs-1
groupJoin:srcObs-2
groupJoin:srcObs-3

分析:源Observable只發射了一條“srcObs-”的數據,有效期爲3s,目標Observable每隔1s發射一條數據,每條數據有效期爲2s。在“srcObs-”有效期間,obs1一共發射了三條數據,都能結合,最後“srcObs-”過期了,obs1發射的數據就捨棄了,所以一共輸出三條。

3. Merge

  使用Merge操作符你可以將多個Observables的輸出合併,就好像它們是一個單個的Observable一樣。Merge可能會讓合併的Observables發射的數據交錯(有一個類似的操作符Concat不會讓數據交錯,它會按順序一個接着一個發射多個Observables的發射物)。

Merge操作符有兩種:

  • merge:任何一個原始Observable的onError通知會被立即傳遞給觀察者,而且會終止合併後的Observable。
        這裏寫圖片描述
  • mergeDelayError: mergeDelayError操作符會保留onError通知直到合併後的Observable所有的數據發射完成,在那時它纔會把onError傳遞給觀察者。
        這裏寫圖片描述

示例代碼:

/*
 * merge:當其中一個Observable發生onError時,就會終止發射數據,並將OnError傳遞給觀察者
 */
Observable<Integer> odds = Observable.just(1, 3, 5);
Observable<Integer> evens = Observable.just(2, 4, 6);
Observable.merge(odds, evens)
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onNext(Integer item) {
                Log.v(TAG, "merge Next: " + item);
            }
            @Override
            public void onError(Throwable error) {
                Log.e(TAG, "merge Error: " + error.getMessage());
            }
            @Override
            public void onCompleted() {
                Log.v(TAG, "merge Sequence complete.");
            }
        });

/*
 * mergeDelayError:當發生onError時,會等待其他Observable將數據發射完,然後纔將onError發送個觀察者
 */
Observable.mergeDelayError(Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for (int i = 0; i < 5; i++) {
            if (i == 3) {
                subscriber.onError(new Throwable("第一個發射onError了"));
            }
            subscriber.onNext(i);
        }
    }
}), Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for (int i = 10; i < 15; i++) {
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
})).subscribe(new Subscriber<Integer>() {
    @Override
    public void onNext(Integer item) {
        Log.v(TAG, "mergeDelayError Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        Log.e(TAG, "mergeDelayError Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.v(TAG, "mergeDelayError Sequence complete.");
    }
});

輸出:

merge Next: 1
merge Next: 3
merge Next: 5
merge Next: 2
merge Next: 4
merge Next: 6
merge Sequence complete.

mergeDelayError Next: 0
mergeDelayError Next: 1
mergeDelayError Next: 2
mergeDelayError Next: 3
mergeDelayError Next: 4
mergeDelayError Next: 10
mergeDelayError Next: 11
mergeDelayError Next: 12
mergeDelayError Next: 13
mergeDelayError Next: 14
mergeDelayError Error: 第一個發射onError了

4. StartWith

  startWith操作符可以在Observable在發射數據之前先發射一個指定的數據序列。它可以接受一個Iterable或者多個Observable作爲函數的參數。
  如果我們傳遞一個Observable給startWith,它會將這個Observable的數據插在原始Observable發射的數據序列之前。(如果你想一個Observable發射的數據末尾追加一個數據序列可以使用Concat操作符。)
    這裏寫圖片描述
示例代碼:

/*
 * 插入一個Observable
 */
Observable<Integer> obs1 = Observable.just(1, 2, 3);
Observable<Integer> obs2 = Observable.just(4, 5, 6);
obs1.startWith(obs2).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
        Log.v(TAG, "onNext:"+integer);
    }
});

/*
 * 插入數據序列(最多接受9個參數)
 */
Observable<String> obs3 = Observable.just("c","d","e");
obs3.startWith("a", "b").subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.v(TAG, "onNext:"+s);
    }
});

輸出:

onNext:4
onNext:5
onNext:6
onNext:1
onNext:2
onNext:3

onNext:a
onNext:b
onNext:c
onNext:d
onNext:e

5. Switch

  將一個發射多個Observables的Observable轉換成另一個單獨的Observable,後者發射那些Observables最近發射的數據項。
   Switch訂閱一個發射多個Observables的Observable。它每次觀察那些Observables中的一個,Switch返回的這個Observable取消訂閱前一個發射數據的Observable,開始發射最近的Observable發射的數據。

  注意:當原始Observable發射了一個新的Observable時(不是這個新的Observable發射了一條數據時),它將取消訂閱之前的那個Observable。這意味着,在後來那個Observable產生之後,前一個Observable發射的數據將被丟棄(就像圖例上的那個黃色圓圈一樣)。

    這裏寫圖片描述

示例代碼:

Observable.switchOnNext(Observable.create(
        new Observable.OnSubscribe<Observable<Long>>() {
            @Override
            public void call(Subscriber<? super Observable<Long>> subscriber) {
                for (int i = 1; i < 3; i++) {
                    //每隔1s發射一個小Observable。小Observable每1s發射一個整數
                    //第一個小Observable將發射6個整數,第二個將發射3個整數
                    subscriber.onNext(Observable.interval(1000, TimeUnit.MILLISECONDS).take(i==1?6:3));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
)).subscribe(new Action1<Long>() {
    @Override
    public void call(Long s) {
        Log.v(TAG, "onNext:"+s);
    }
});

輸出:

onNext:0
onNext:0
onNext:1
onNext:2

從Log可以看出,第一個Observable每隔1s發射一個數據,總共發射6條數據;第二個Observable正好在第一個Observable發射1的時候產生了,這時候將不再訂閱第一個Observable,所以第一個Observable只發射了一個0,後面的5個數據都被捨棄了。

6. Zip

  通過一個函數將多個Observables的發射物結合到一起,基於這個函數的結果爲每個結合體發射單個數據項。
    這裏寫圖片描述
  Zip操作符返回一個Obversable,它使用這個函數按順序結合兩個或多個Observables發射的數據項,然後它發射這個函數返回的結果。它按照嚴格的順序發射數據。它只發射與發射數據項最少的那個Observable一樣多的數據。
RxJava將這個操作符實現爲zip(static)和zipWith(非static):

  • zip

    • Javadoc: zip(Iterable,FuncN)
    • Javadoc: zip(Observable,FuncN)
    • Javadoc: zip(Observable,Observable,Func2) (最多可以有九個Observables參數)

  zip的最後一個參數接受每個Observable發射的一項數據,返回被壓縮後的數據,它可以接受一到九個參數:一個Observable序列,或者一些發射Observable的Observables。
    這裏寫圖片描述

  • zipWith

    • Javadoc: zipWith(Observable,Func2)
    • Javadoc: zipWith(Iterable,Func2)

  zipWith和zip的區別是zipWith不是static的,它必須由一個Observable對象調用,zipWith操作符總是接受兩個參數,第一個參數是一個Observable或者一個Iterable。
    這裏寫圖片描述

示例代碼:

Observable obs1 = Observable.just(1,2,3,4);
Observable obs2 = Observable.just(10,20,30,40);
/*
 * zip(Observable,FuncN):
 * ①.能接受1~9個Observable作爲參數,或者單個Observables列表作爲參數;
 *    Func函數的作用就是從每個Observable中獲取一個數據進行結合後發射出去;
 * ②.小Observable的每個數據只能組合一次,如果第二個小Observable發射數據的時候,
 *    第一個還沒有發射,將要等待第一個發射數據後才能組合;
 */
Observable.zip(obs1, obs2,
        new Func2<Integer, Integer, String>() {
            //使用一個函數結合每個小Observable的一個數據(每個數據只能組合一次),然後發射這個函數的返回值
            @Override
            public String call(Integer int1, Integer int2) {
                return int1+"-"+int2;
            }
        }).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.v(TAG, "zip:"+s);
    }
});

/*
 * zipWith(Observable,Func2):
 * ①.zipWith不是static的,必須由一個Observable對象調用
 * ②.如果要組合多個Observable,可以傳遞Iterable
 */
obs1.zipWith(obs2, new Func2<Integer, Integer, String>() {
    //使用一個函數結合每個小Observable的一個數據(每個數據只能組合一次),然後發射這個函數的返回值
    @Override
    public String call(Integer int1, Integer int2) {
        return int1+"-"+int2;
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.v(TAG, "zipWith:"+s);
    }
});

輸出:

zip:1-10
zip:2-20
zip:3-30
zip:4-40

zipWith :1-10
zipWith :2-20
zipWith :3-30
zipWith :4-40

**有問題請留言,有幫助請點贊(^__^)**

#源碼下載:

https://github.com/openXu/RxJavaTest

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