RxJava操作符系列四

Code4Android發表於2016-12-15

RxJava操作符系列傳送門

RxJava操作符原始碼
RxJava操作符系列一
RxJava操作符系列二
RxJava操作符系列三

前言

在上一篇文章我們主要介紹的是RxJava的一些過濾操作符,若將過濾操作和轉換操作一起使用,能處理複雜的的業務邏輯,在文章中所舉的例子都是都是很簡單的邏輯,簡單的讓人感覺這樣寫沒必要,當然這這是為了便於理解操作符的含義,只有理解了這些基礎上我們才能做更復雜的操作。相信通過學習,能感悟出RxJava的強大。讓我們繼續開啟學習之旅吧。

Merge

該操作符可以將多個Observables的輸出合併,就好像它們是一個單個的Observable一樣,他可能讓我們讓合併的Observables發射的資料交錯(順序發生變化),在此過程中任何一個原始Observable的onError通知都會被立即傳遞給觀察者,而且會終止合併後的Observable。

        Observable observable=Observable.just(1,2);
        Observable observable1=Observable.just(6,7);
        Observable.merge(observable, observable1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString() );
                    }

                    @Override
                    public void onNext(Integer s) {
                        Log.e(TAG, "onNext: "+s);
                    }
                });複製程式碼

輸出日誌資訊

onNext: 1
onNext: 2
onNext: 6
onNext: 7
onCompleted:複製程式碼

如果我們此時在建立一個Obserable如下

        Observable observable2 = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                try {
                    Thread.sleep(500);
                    subscriber.onNext(200);
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).subscribeOn(Schedulers.newThread());複製程式碼

然後將merge(observable, observable1)更改為merge(observable2,observable, observable1)
再次執行,發現雖然observable2是第一個引數,但是輸出卻是在最後一個輸出。

MergeDelayError

對於merge操作符的任何一個的Observable發射了onError通知終止了,merge操作符生成的Observable也會立即以onError通知終止。如果你想讓它繼續發射資料,在最後才報告錯誤,可以使用mergeDelayError。我們先使用merge將observable2的建立程式碼更改下面程式碼,依然執行merge(observable2,observable, observable1)。

        Observable observable2 = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

               try {
                    subscriber.onNext(100);
                    subscriber.onError(new Throwable("error"));
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }

            }
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());複製程式碼

輸出日誌資訊

onError: java.lang.Throwable: error複製程式碼

由於observable2 的異常,導致observable和 observable1被中斷。
那麼如果在這種情況下依然傳送資料該怎麼辦呢,MergeDelayError就可以達到這樣的效果,看如下實現程式碼。最後提醒下MergeDelayError的使用有個坑,就是subscribeOn和observeOn的呼叫問題,如果先mergeDelayError之後再用subscribeOn和observeOn指定排程器發現該操作符並不起作用。需要在單獨建立Observable時使用,如下示例程式碼

        Observable observable = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

               try {
                    subscriber.onNext(100);
                    subscriber.onError(new Throwable("error"));
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }

            }
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable observable3=Observable.just(6,7,8,9).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable.merge(observable,observable1)
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString() );
                    }

                    @Override
                    public void onNext(Integer s) {
                        Log.e(TAG, "onNext: "+s);
                    }
                });複製程式碼

輸出日誌資訊

onNext: 6
onNext: 7
onNext: 8
onNext: 9
onError: java.lang.Throwable: error複製程式碼

#Concat
該操作符和merge操作符相似,不同之處就是該操作符按順序一個接著一個發射多個Observables的發射物。保證順序性。

Observable observableA = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

                try {
                    subscriber.onNext(100);
                    Thread.sleep(500);
                    subscriber.onNext(200);
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }
            }
  }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable<Integer> observableB = Observable.range(7, 2);
        Observable.concat(observableA, observableB).subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: concat");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: concat");
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "onNext: concat" + integer);
            }
        });複製程式碼

輸出日誌資訊

onNext: concat100
onNext: concat200
onNext: concat7
onNext: concat8
onCompleted: concat複製程式碼

這樣就保證了順序性,如果用merge的話,100和200應該在7和8後輸出。

Zip

該操作符返回一個Obversable,它使用這個函式按順序結合兩個或多個Observables發射的資料項,然後它發射這個函式返回的結果。它按照嚴格的順序應用這個函式。它只發射與發射資料項最少的那個Observable一樣多的資料,假如兩個Observable資料分佈為4項,5項,則最終合併是4項。如下示例程式碼

List<String> names = new ArrayList<>();
        List<Integer> ages = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            names.add("張三" + i);
            ages.add(20 + i);
        }
        ages.add(15);
        Observable observable1 = Observable.from(names).subscribeOn(Schedulers.io());
        Observable observable2 = Observable.from(ages).subscribeOn(Schedulers.io());
        //Func2第三個引數是返回值型別
        Observable.zip(observable1, observable2, new Func2<String, Integer, String>() {
            @Override
            public String call(String name, Integer age) {
                return name + ": " + age;
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: ");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ");
            }

            @Override
            public void onNext(String o) {
                Log.e(TAG, "onNext: " + o);
            }
        });複製程式碼

輸出日誌資訊

onNext: 張三0: 20
onNext: 張三1: 21
onNext: 張三2: 22
onNext: 張三3: 23
onNext: 張三4: 24
onCompleted:複製程式碼

StartWith

該操作符作用是在一個Observable在發射資料之前先發射一個指定的資料序列。如下

Observable.range(1,3).startWith(11,12).subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ");
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "onNext: "+integer );
            }
        });複製程式碼

輸出日誌資訊

onNext: 11
onNext: 12
onNext: 1
onNext: 2
onNext: 3
onCompleted:複製程式碼

CombineLatest

RxJava操作符系列四
這裡寫圖片描述

操作符行為類似於zip,但是隻有當原始的Observable中的每一個都發射了一條資料時zip才發射資料。CombineLatest則在原始的Observable中任意一個發射了資料時發射一條資料。當原始Observables的任何一個發射了一條資料時,CombineLatest使用一個函式結合它們最近發射的資料,然後發射這個函式的返回值。通過上面的圖應該更容易理解。
示例程式碼

 Observable<Integer> observableA = Observable.range(1, 4);
        Observable<Integer> observableB = Observable.range(10, 5);
        Observable.combineLatest(observableA, observableB, new Func2<Integer, Integer, String>() {
            @Override
            public String call(Integer integer, Integer integer2) {
                Log.e(TAG, "call: combineLatest");
                return "observableA:" + integer + "  observableB:" + integer2;
            }
        }).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Log.e(TAG, "call: combineLatest" + s);
            }
        });複製程式碼

輸出日誌資訊

call: combineLatest
call: combineLatestobservableA:4  observableB:10
call: combineLatest
call: combineLatestobservableA:4  observableB:11
call: combineLatest
call: combineLatestobservableA:4  observableB:12
call: combineLatest
call: combineLatestobservableA:4  observableB:13
call: combineLatest
call: combineLatestobservableA:4  observableB:14複製程式碼

Join

該操作符只要在另一個Observable發射的資料定義的時間視窗內,這個Observable發射了一條資料,就結合兩個Observable發射的資料.例如A作為基礎視窗,當A發射了資料1,2,3,4,5時,B發射了一個資料a.則此時合併資料(1,a),(2,a),(3,a),(4,a),(5,a),此時將視窗清楚並重新開啟一個視窗迴圈此種操作直到資料輸出完畢。
示例程式碼

Observable<Integer> observableA = Observable.range(1, 2).subscribeOn(Schedulers.newThread());
        Observable<Integer> observableB = Observable.range(7, 3).subscribeOn(Schedulers.newThread());
        observableA.join(observableB, new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                Log.e(TAG, "call: A" + integer +"   "+ Thread.currentThread().getName());
                return Observable.just(integer).delay(1,TimeUnit.SECONDS);
            }
        }, new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                Log.e(TAG, "call: B" + integer +"   "+ Thread.currentThread().getName());
                return Observable.just(integer).delay(1,TimeUnit.SECONDS);
            }
        }, new Func2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) {
                Log.e(TAG, "call:AjoinB A: " + integer + " B:" + integer2 + Thread.currentThread().getName());
                return integer+integer2;
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString());
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e(TAG, "onNext: "+integer);
                    }
                });複製程式碼

輸出日誌資訊

call: A1   RxNewThreadScheduler-4
call: A2   RxNewThreadScheduler-4
call: B7   RxNewThreadScheduler-5
call:AjoinB A: 1 B:7RxNewThreadScheduler-5
call:AjoinB A: 2 B:7RxNewThreadScheduler-5
call: B8   RxNewThreadScheduler-5
call:AjoinB A: 1 B:8RxNewThreadScheduler-5
call:AjoinB A: 2 B:8RxNewThreadScheduler-5
call: B9   RxNewThreadScheduler-5
onNext: 8
onNext: 9
onNext: 9
call:AjoinB A: 1 B:9RxNewThreadScheduler-5
call:AjoinB A: 2 B:9RxNewThreadScheduler-5
onNext: 10
onNext: 10
onNext: 11
onCompleted:複製程式碼

switchOnNext

RxJava操作符系列四
這裡寫圖片描述

該操作符將一個發射多個Observables的Observable轉換成另一個單獨的Observable,後者發射那些Observables最近發射的資料項。當有新的Observable開始訂閱時,會取消之前的訂閱,並將資料丟棄。如下示例

        Observable<Observable<Long>> observable = Observable.interval(0, 500, TimeUnit.MILLISECONDS).map(new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
                //每隔200毫秒產生一組資料(0,10,20,30,40)
                Log.e(TAG, "call1: "+aLong);
                return Observable.interval(0, 200, TimeUnit.MILLISECONDS).map(new Func1<Long, Long>() {
                    @Override
                    public Long call(Long aLong) {
                        Log.e(TAG, "call2: "+aLong );
                        return aLong * 10;
                    }
                }).take(5);
            }
        }).take(2);
        Observable.switchOnNext(observable).subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: SwitchOnNext" );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: SwitchOnNext");
            }

            @Override
            public void onNext(Long aLong) {
                Log.e(TAG, "onNext: SwitchOnNext  "+aLong);
            }
        });複製程式碼

輸出日誌資訊

call1: 0
call2: 0
onNext: SwitchOnNext  0
call2: 1
onNext: SwitchOnNext  10
call2: 2
onNext: SwitchOnNext  20
call1: 1
call2: 0
onNext: SwitchOnNext  0
call2: 1
onNext: SwitchOnNext  10
call2: 2
onNext: SwitchOnNext  20
call2: 3
onNext: SwitchOnNext  30
call2: 4
onNext: SwitchOnNext  40
onCompleted: SwitchOnNext複製程式碼

今天的這篇文章就到此結束,歡迎大家閱讀,若發現文中有錯誤的地方歡迎留言提出,感謝。

相關文章