RxJava操作符之組合操作符(六)

前言

上一篇文章我們學(xué)習(xí)了過濾類操作符,本篇我們將一起來學(xué)習(xí)RxJava組合類操作符。組合操作符主要是用來同時(shí)處理多個(gè)Observable,將他們進(jìn)行組合創(chuàng)建出新的滿足我們需求的Observable,一起來看下都有哪些。

組合操作符

Merge

merge操作符,將兩個(gè)Observable要發(fā)射的觀測序列合并為一個(gè)序列進(jìn)行發(fā)射。按照兩個(gè)序列每個(gè)元素的發(fā)射時(shí)間先后進(jìn)行排序,同一時(shí)間點(diǎn)發(fā)射的元素則是無序的。

//將一個(gè)發(fā)送字母的Observable與發(fā)送數(shù)字的Observable合并發(fā)射
final String[] words = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I"};
//字母Observable,每200ms發(fā)射一次
Observable<String> wordSequence = Observable.interval(200, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, String>() {
            @Override
            public String call(Long position) {
                return words[position.intValue()];
            }
        })
        .take(words.length);
//數(shù)字Observable,每500ms發(fā)射一次
Observable<Long> numberSequence = Observable.interval(500, TimeUnit.MILLISECONDS).take(4);
Observable.merge(wordSequence, numberSequence)
        .subscribe(new Action1<Serializable>() {
            @Override
            public void call(Serializable serializable) {
                Log.e("rx_test", "merge:" + serializable.toString());
            }
        });

輸出結(jié)果:

merge:A
merge:B
merge:0
merge:C
merge:D
merge:E
merge:1
merge:F
merge:G
merge:2
merge:H
merge:I
merge:3

原理圖:


merge操作符還有一種入?yún)erge(Observable[]),可傳入含有多個(gè)Observable的集合,merge操作符也可將這多個(gè)Observable的序列合并后發(fā)射。

MergeDelayError

mergeDelayError操作符,與merge功能類似,都是用來合并Observable的。不同之處在于mergeDelayError操作符在合并過程中發(fā)生異常的話不會(huì)立即停止合并,而會(huì)在所有元素合并發(fā)射完畢之后再發(fā)射異常。但發(fā)生異常的那個(gè)Observable就不會(huì)發(fā)射數(shù)據(jù)了。

//字母Observable,每200ms發(fā)射一次,模擬過程中產(chǎn)生一個(gè)異常
Observable<String> wordSequence = Observable.interval(200, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, String>() {
            @Override
            public String call(Long position) {
                Long cache = position;
                if (cache == 3) {
                    cache = cache / 0;
                }
                return words[position.intValue()];
            }
        })
        .take(words.length);
//數(shù)字Observable,每500ms發(fā)射一次
Observable<Long> numberSequence = Observable.interval(500, TimeUnit.MILLISECONDS).take(4);
Observable.mergeDelayError(wordSequence, numberSequence)
        .subscribe(new Action1<Serializable>() {
            @Override
            public void call(Serializable serializable) {
                Log.e("rx_test", "mergeDelayError:" + serializable.toString());
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                Log.e("rx_test", "mergeDelayError:" + throwable.getMessage());
            }
        }, new Action0() {
            @Override
            public void call() {
                Log.e("rx_test", "mergeDelayError:onComplete");
            }
        });

輸出結(jié)果:

mergeDelayError:A
mergeDelayError:B
mergeDelayError:0
mergeDelayError:C
mergeDelayError:1
mergeDelayError:2
mergeDelayError:3
mergeDelayError:divide by zero

由輸出結(jié)果可看出,wordSequence在發(fā)射到C時(shí)拋出了一個(gè)異常,停止發(fā)射其剩下的數(shù)據(jù),但合并沒有停止。合并完成之后這個(gè)異常才被發(fā)射了出來。

原理圖:


Concat

concat操作符,將多個(gè)Obserbavle發(fā)射的數(shù)據(jù)進(jìn)行合并后發(fā)射,類似于merge操作符。但concat操作符是將Observable依次發(fā)射,是有序的。

Observable<String> wordSequence = Observable.just("A", "B", "C", "D", "E");
Observable<Integer> numberSequence = Observable.just(1, 2, 3, 4, 5);
Observable<String> nameSequence = Observable.just("Sherlock", "Holmes", "Xu", "Lei");
Observable.concat(wordSequence, numberSequence, nameSequence)
        .subscribe(new Action1<Serializable>() {
            @Override
            public void call(Serializable serializable) {
                Log.e("rx_test", "concat:" + serializable.toString());
            }
        });

輸出結(jié)果:

concat:A
concat:B
concat:C
concat:D
concat:E
concat:1
concat:2
concat:3
concat:4
concat:5
concat:Sherlo
concat:Holmes
concat:Xu
concat:Lei

原理圖:

Zip

zip(Observable, Observable, Func2)操作符,根據(jù)Func2中的call()方法規(guī)則合并兩個(gè)Observable的數(shù)據(jù)項(xiàng)并發(fā)射。
注意:若其中一個(gè)Observable數(shù)據(jù)發(fā)送結(jié)束或出現(xiàn)異常后,另一個(gè)Observable也會(huì)停止發(fā)射數(shù)據(jù)。

Observable<String> wordSequence = Observable.just("A", "B", "C", "D", "E");
Observable<Integer> numberSequence = Observable.just(1, 2, 3, 4, 5, 6);
Observable.zip(wordSequence, numberSequence, new Func2<String, Integer, String>() {
    @Override
    public String call(String s, Integer integer) {
        return s + integer;
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.e("rx_test", "zip:" + s);
    }
});

輸出結(jié)果:

zip:A1
zip:B2
zip:C3
zip:D4
zip:E5

由輸出結(jié)果可看出numberSequence觀測序列最后的6并沒有發(fā)射出來,由于wordSequence觀測序列已發(fā)射完所有數(shù)據(jù),所以組合序列也停止發(fā)射數(shù)據(jù)了。

原理圖:


StartWith

startWith操作符,用于在源Observable發(fā)射的數(shù)據(jù)前,插入指定的數(shù)據(jù)并發(fā)射。

Observable.just(4, 5, 6, 7)
        .startWith(1, 2, 3)
        .subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                Log.e("rx_test", "startWith:" + integer);
            }
        });

輸出結(jié)果:

startWith:1
startWith:2
startWith:3
startWith:4
startWith:5
startWith:6
startWith:7

原理圖:


startWith還有兩種入?yún)ⅲ?p>

  • startWith(Iterable<T>):可在源Observable發(fā)射的數(shù)據(jù)前插入Iterable數(shù)據(jù)并發(fā)射。
  • startWith(Observable<T>):可在源Observable發(fā)射的數(shù)據(jù)前插入另一Observable發(fā)射的數(shù)據(jù)并發(fā)射。

SwitchOnNext

switchOnNext操作符,用來將一個(gè)發(fā)射多個(gè)小Observable的源Observable轉(zhuǎn)化為一個(gè)Observable,然后發(fā)射多個(gè)小Observable所發(fā)射的數(shù)據(jù)。若小Observable正在發(fā)射數(shù)據(jù)時(shí),源Observable又發(fā)射了新的小Observable,則前一個(gè)小Observable還未發(fā)射的數(shù)據(jù)會(huì)被拋棄,直接發(fā)射新的小Observable所發(fā)射的數(shù)據(jù),上例子。

//每隔500ms產(chǎn)生一個(gè)Observable
Observable<Observable<Long>> observable = Observable.interval(500, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
                //每隔200毫秒產(chǎn)生一組數(shù)據(jù)(0,10,20,30,40)
                return Observable.interval(200, TimeUnit.MILLISECONDS)
                        .map(new Func1<Long, Long>() {
                            @Override
                            public Long call(Long aLong) {
                                return aLong * 10;
                            }
                        }).take(5);
                }
        }).take(2);
        
Observable.switchOnNext(observable)
        .subscribe(new Action1<Long>() {
            @Override
            public void call(Long aLong) {
                Log.e("rx_test", "switchOnNext:" + aLong);
            }
        });

輸出結(jié)果:

switchOnNext:0
switchOnNext:10
switchOnNext:0
switchOnNext:10
switchOnNext:20
switchOnNext:30
switchOnNext:40

由輸出結(jié)果發(fā)現(xiàn)第一個(gè)小Observable打印到10則停止了發(fā)射數(shù)據(jù),說明其發(fā)射到10時(shí),新的小Observable被創(chuàng)建了出來,第一個(gè)小Observable則被中斷發(fā)射,開始發(fā)射新的小Observable的數(shù)據(jù)。

原理圖:


CombineLatest

combineLatest操作符,用于將兩個(gè)Observale最近發(fā)射的數(shù)據(jù)以Func2函數(shù)的規(guī)則進(jìn)行組合并發(fā)射。

//引用merge的例子
final String[] words = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I"};
Observable<String> wordSequence = Observable.interval(300, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, String>() {
            @Override
            public String call(Long position) {
                return words[position.intValue()];
            }
        })
        .take(words.length);
Observable<Long> numberSequence = Observable.interval(500, TimeUnit.MILLISECONDS)
        .take(5);
Observable.combineLatest(wordSequence, numberSequence,
        new Func2<String, Long, String>() {
            @Override
            public String call(String s, Long aLong) {
                return s + aLong;
            }
        })
        .subscribe(new Action1<Serializable>() {
            @Override
            public void call(Serializable serializable) {
                Log.e("rx_test", "combineLatest:" + serializable.toString());
            }
        });

輸出結(jié)果:

combineLatest:A0
combineLatest:B0
combineLatest:C0
combineLatest:C1
combineLatest:D1
combineLatest:E1
combineLatest:E2
combineLatest:F2
combineLatest:F3
combineLatest:G3
combineLatest:H3
combineLatest:H4
combineLatest:I4

如果將wordSequence與numberSequence的入?yún)㈨樞蚧Q,輸出結(jié)果也會(huì)不同:

combineLatest:0A
combineLatest:0B
combineLatest:0C
combineLatest:1C
combineLatest:1D
combineLatest:2D
combineLatest:2E
combineLatest:2F
combineLatest:3F
combineLatest:3G
combineLatest:3H
combineLatest:4H
combineLatest:4I

wordSequence每300ms發(fā)射一個(gè)字符,numberSequence每500ms發(fā)射一個(gè)數(shù)字。可能有些碼友不知道這個(gè)輸出結(jié)果怎么來的,這個(gè)操作符確實(shí)不太好理解。我們來看一下這個(gè)原理圖就很清楚了。

原理圖:

Join

join(Observable, Func1, Func1, Func2)操作符,類似于combineLatest操作符,用于將ObservableA與ObservableB發(fā)射的數(shù)據(jù)進(jìn)行排列組合。但join操作符可以控制Observable發(fā)射的每個(gè)數(shù)據(jù)的生命周期,在每個(gè)發(fā)射數(shù)據(jù)的生命周期內(nèi),可與另一個(gè)Observable發(fā)射的數(shù)據(jù)按照一定規(guī)則進(jìn)行合并,來看下join的幾個(gè)入?yún)ⅰ?/p>

  • Observable:需要與源Observable進(jìn)行組合的目標(biāo)Observable。
  • Func1:接收從源Observable發(fā)射來的數(shù)據(jù),并返回一個(gè)Observable,這個(gè)Observable的聲明周期決定了源Obsrvable發(fā)射出來的數(shù)據(jù)的有效期;
  • Func1:接收目標(biāo)Observable發(fā)射來的數(shù)據(jù),并返回一個(gè)Observable,這個(gè)Observable的聲明周期決定了目標(biāo)Obsrvable發(fā)射出來的數(shù)據(jù)的有效期;
  • Func2:接收從源Observable和目標(biāo)Observable發(fā)射出來的數(shù)據(jù),并將這兩個(gè)數(shù)據(jù)按自定的規(guī)則組合后返回。
//產(chǎn)生字母的序列,周期為1000ms
String[] words = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
Observable<String> observableA = Observable.interval(1000, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, String>() {
            @Override
            public String call(Long aLong) {
                return words[aLong.intValue()];
            }
        }).take(8);
//產(chǎn)0,1,2,3,4,5,6,7的序列,延時(shí)500ms發(fā)射,周期為1000ms
Observable<Long> observableB = Observable.interval(500, 1000, TimeUnit.MILLISECONDS)
        .map(new Func1<Long, Long>() {
            @Override
            public Long call(Long aLong) {
                return aLong;
            }
        }).take(words.length);
//join
observableA.join(observableB,
        new Func1<String, Observable<Long>>() {
            @Override
            public Observable<Long> call(String s) {
                //ObservableA發(fā)射的數(shù)據(jù)有效期為600ms
                return Observable.timer(600, TimeUnit.MILLISECONDS);
            }
        },
        new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
                //ObservableB發(fā)射的數(shù)據(jù)有效期為600ms
                return Observable.timer(600, TimeUnit.MILLISECONDS);
            }
        },
        new Func2<String, Long, String>() {
            @Override
            public String call(String s, Long aLong) {
                return s + aLong;
            }
        }
).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.e("rx_test", "join:" + s);
    }
});

join操作符的組合方式類似于數(shù)學(xué)上的排列組合規(guī)則,以O(shè)bservableA為基準(zhǔn)源Observable,按照其自身周期發(fā)射數(shù)據(jù),且每個(gè)發(fā)射出來的數(shù)據(jù)都有其有效期。而ObservableB每發(fā)射出來一個(gè)數(shù)據(jù),都與A發(fā)射出來的并且還在有效期內(nèi)的數(shù)據(jù)按Func2函數(shù)中的規(guī)則進(jìn)行組合,B發(fā)射出來的數(shù)據(jù)也有其有效期。最后再將結(jié)果發(fā)射給觀察者進(jìn)行處理。

輸出結(jié)果:

join:A0
join:A1
join:B1
join:B2
join:C2
join:C3
join:D3
join:D4
join:E4
join:E5
join:F5
join:F6
join:G6
join:G7
join:H7

原理圖:

GroupJoin

groupJoin操作符,類似于join操作符,區(qū)別在于第四個(gè)參數(shù)Func2的傳入函數(shù)不同,對join之后的結(jié)果包裝了一層小的Observable,便于用戶再次進(jìn)行一些過濾轉(zhuǎn)換等操作再發(fā)射給Observable。

observableA.groupJoin(observableB,
        new Func1<String, Observable<Long>>() {
            @Override
            public Observable<Long> call(String s) {
                return Observable.timer(600, TimeUnit.MILLISECONDS);
            }
        },
        new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
                return Observable.timer(600, TimeUnit.MILLISECONDS);
            }
        },
        new Func2<String, Observable<Long>, Observable<String>>() {
            @Override
            public Observable<String> call(final String s, Observable<Long> longObservable) {
                return longObservable.map(new Func1<Long, String>() {
                    @Override
                    public String call(Long aLong) {
                        return s + aLong;
                    }
                });
            }
        })
        .subscribe(new Action1<Observable<String>>() {
            @Override
            public void call(Observable<String> stringObservable) {
                stringObservable.subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.e("rx_test", "groupJoin:" + s);
                    }
                });
            }
        });

輸出結(jié)果:

groupJoin:A0
groupJoin:A1
groupJoin:B1
groupJoin:B2
groupJoin:C2
groupJoin:C3
groupJoin:D3
groupJoin:D4
groupJoin:E4
groupJoin:E5
groupJoin:F5
groupJoin:F6
groupJoin:G6
groupJoin:G7
groupJoin:H7

原理圖:


總結(jié)

到此,本篇關(guān)于RxJava的常用組合類操作符就講解完畢了。通過以上四篇文章對RxJava四類操作符的學(xué)習(xí),相信大家已經(jīng)基本掌握RxJava如何使用了。實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),下一篇我們來一起上項(xiàng)目看看實(shí)踐中如何使用RxJava。

技術(shù)渣一枚,有寫的不對的地方歡迎大神們留言指正,有什么疑惑或者建議也可以在我Github上RxJavaDemo項(xiàng)目Issues中提出,我會(huì)及時(shí)回復(fù)。

附上RxJavaDemo的地址:
RxJavaDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容