Rxjava3文檔級教程二: 操作符全解

商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

Rxjava3文檔級教程一: 介紹和基本使用

Rxjava3文檔級教程二: 操作符全解

Rxjava3文檔級教程三: 實戰演練

目錄

1 前言

1.1 用操作符組合Observable

1.2 操作符分類

1.2.1 創建操作

1.1.2 變換操作

1.1.3 過濾操作

1.1.4 組合操作

1.1.5 錯誤處理

1.1.6 輔助操作

1.1.7 條件和布爾操作

1.1.8 算術和聚合操作

1.1.9 連接操作

1.1.10 轉換操作

1.1.11 操作符決策樹

2 創建操作符

2.1 create()

2.2 from()

2.3 just()

2.4 defer()

2.5 range()

2.6 interval()

2.7 repeat()

2.8 timer()

3 過濾操作符

3.1 skip / skipLast

3.2 debounce(去抖動)

3.3 distinct(去重)

3.4 elementAt(獲取指定位置元素)

3.5 filter(過濾)

3.6 first(第一個)

3.7 last(最後一個)

3.8 ignoreElements & ignoreElement(忽略元素)

3.9 ofType(過濾類型)

3.10 sample

3.11 throttleFirst & throttleLast & throttleWithTimeout & throttleLatest

3.12 take & takeLast

3.13 timeout(超時)

 3.14 merge/concat

 3.15 zip()

 3.16 startWith()

 3.17 join()

4 連接/組合操作符

4.1 startWith()

4.2 merge / mergeWith

4.3 zip()

4.4 combineLatest()

4.5 switchOnNext()

5 變換/轉換操作符

5.1 map()

5.2 flatMap() / concatMap()

5.3 groupBy()

5.4 scan()

5.5 buffer()

5.6 window()

5.7 cast()

5.8 concatMapDelayError

5.9 concatMapCompletable()

5.10 concatMapCompletableDelayError()

5.11 flattenAsFlowable & flattenAsObservable

6 處理操作符

6.1 onErrorReturn()

6.2 onErrorReturnItem()

6.3 onExceptionResumeNext()

6.4 retry()

6.5 retryUntil()

6.6  retryWhen()

補充1:Rxjava3包結構的變動:

補充2:

參考文章:


1 前言

1.1 用操作符組合Observable

對於ReactiveX來說,Observable和Observer僅僅是個開始,它們本身不過是標準觀察者模式的一些輕量級擴展,目的是爲了更好的處理事件序列。

ReactiveX真正強大的地方在於它的操作符,操作符讓你可以變換、組合、操縱和處理Observable發射的數據。

Rx的操作符讓你可以用聲明式的風格組合異步操作序列,它擁有回調的所有效率優勢,同時又避免了典型的異步系統中嵌套回調的缺點。

下面是常用的操作符列表:

  1. 創建操作 Create, Defer, Empty/Never/Throw, From, Interval, Just, Range, Repeat, Start, Timer

  2. 變換操作 Buffer, FlatMap, GroupBy, Map, Scan和Window

  3. 過濾操作 Debounce, Distinct, ElementAt, Filter, First, IgnoreElements, Last, Sample, Skip, SkipLast, Take, TakeLast

  4. 組合操作 And/Then/When, CombineLatest, Join, Merge, StartWith, Switch, Zip

  5. 錯誤處理 Catch和Retry

  6. 輔助操作 Delay, Do, Materialize/Dematerialize, ObserveOn, Serialize, Subscribe, SubscribeOn, TimeInterval, Timeout, Timestamp, Using

  7. 條件和布爾操作 All, Amb, Contains, DefaultIfEmpty, SequenceEqual, SkipUntil, SkipWhile, TakeUntil, TakeWhile

  8. 算術和集合操作 Average, Concat, Count, Max, Min, Reduce, Sum

  9. 轉換操作 To

  10. 連接操作 Connect, Publish, RefCount, Replay

  11. 反壓操作,用於增加特殊的流程控制策略的操作符

這些操作符並不全都是ReactiveX的核心組成部分,有一些是語言特定的實現或可選的模塊。

1.2 操作符分類

ReactiveX的每種編程語言的實現都實現了一組操作符的集合。不同的實現之間有很多重疊的部分,也有一些操作符只存在特定的實現中。每種實現都傾向於用那種編程語言中他們熟悉的上下文中相似的方法給這些操作符命名。

本文首先會給出ReactiveX的核心操作符列表和對應的文檔鏈接,後面還有一個決策樹用於幫助你根據具體的場景選擇合適的操作符。最後有一個語言特定實現的按字母排序的操作符列表。

如果你想實現你自己的操作符,可以參考這裏:實現自定義操作符

1.2.1 創建操作

用於創建Observable的操作符

1.1.2 變換操作

這些操作符可用於對Observable發射的數據進行變換,詳細解釋可以看每個操作符的文檔

1.1.3 過濾操作

這些操作符用於從Observable發射的數據中進行選擇

1.1.4 組合操作

組合操作符用於將多個Observable組合成一個單一的Observable

1.1.5 錯誤處理

這些操作符用於從錯誤通知中恢復

1.1.6 輔助操作

一組用於處理Observable的操作符

1.1.7 條件和布爾操作

這些操作符可用於單個或多個數據項,也可用於Observable

1.1.8 算術和聚合操作

這些操作符可用於整個數據序列

1.1.9 連接操作

一些有精確可控的訂閱行爲的特殊Observable

1.1.10 轉換操作

1.1.11 操作符決策樹

幾種主要的需求

這個頁面展示了創建Observable的各種方法。

對RxJava而言,操作符的相關內容Rxjava3 or 2 其實沒什麼改動,大部分Rxjava2的操作符都沒變,即使有所變動,也只是包名或類名的改動。上面常見的操作符也可以直接從文檔中查看用法,下面總結一些常用的操作符進行。


2 創建操作符

create() 創建最簡單的事件流
from() 創建事件流,可發送不同類型的數據流
just() 創建事件流,可發送多個參數的數據流
defer() 創建事件流,可緩存可激活事件流
range() 創建事件流,可發送範圍內的數據流
interval() 創建延時重複的事件流
repeat() 創建可重複次數的事件流
timer() 創建一次延時的事件流

注意:interval()、timer()、delay()的區別

  • interval():用於創建事件流,週期性重複發送
  • timer():用於創建事件流,延時發送一次
  • delay():用於事件流中,可以延時某次事件流的發送

2.1 create()

創建Observable最原始的方式,onNext/onComplete/onError方法可完全自由控制。在Rxjava3文檔級教程:入門到掌握 (一 基本用法 )中,被觀察者的創建基本都用的這種方式,不再重寫贅述。

2.2 from()

        String[] stringArray = {"a", "b", "c"};
        Observable.fromArray(stringArray);
        Observable.fromArray("a", "b", "c");
        Observable.fromArray(1, 2, 3, 4);

fromIterable方法參數爲實現Iterable接口的類,如List/Map/Set等集合類。

        String[] strings = {"a", "b", "c"};
        List<String> listString = Arrays.asList(strings);
        Observable.fromIterable(listString);

2.3 just()

just重載了多個參數數量不同的方法,最大可帶10個參數,just實際上同樣是調用的fromArray方法;

    Observable.just(1, 2, 3, 4)
            .subscribe(new Consumer<Integer>() {
                @Override
                public void accept(Integer integer) throws Exception {
                    Log.i("lucas", interger + "");
                }
            });

2.4 defer()

defer確保了Observable代碼在被訂閱後才執行(而不是創建後立即執行)。

2.5 range()

        //發送從10開始的整數,發送4個(發到13)
        Observable.range(10, 4)
                .subscribe(integer ->  Log.i("lucas", ""+integer));
        //發送從10開始的長整型數,發送6個(發到15)
        Observable.rangeLong(10, 6)
                .subscribe(integer ->  Log.i("lucas", ""+integer));

2.6 interval()

interval用於定時發送

		//每3秒發個自增整數
        Observable.interval(3, TimeUnit.SECONDS);
        //初始延時1秒,每3秒發一個自增整數
        Observable.interval(1, 3, TimeUnit.SECONDS);
		//初始延時2秒,後每1秒發一個從10開始的整數,發5個(發到14)停止
        Observable.intervalRange(10, 5, 2, 1, TimeUnit.SECONDS);

2.7 repeat()

repeat操作符可以重複發送指定次數的某個事件流,repeat操作符默認在trampoline調度器上執行,repeat默認重複次數爲Long.MAX_VALUE,可使用重載方法指定次數以及使用repeatUntil指定條件。

        //一直重複
        Observable.fromArray(1, 2, 3, 4).repeat();
        //重複發送5次
        Observable.fromArray(1, 2, 3, 4).repeat(5);
        //重複發送直到符合條件時停止重複
        Observable.fromArray(1, 2, 3, 4).repeatUntil(new BooleanSupplier() {
			@Override
			public boolean getAsBoolean() throws Exception {
				//自定判斷條件,爲true即可停止,默認爲false
				return false;
			}
		});

2.8 timer()

timer用於延時發送。

        //延時3秒後,發送一個整數0
        Observable.timer(3, TimeUnit.SECONDS);

3 過濾操作符

過濾操作符主要是指對數據源進行選擇和過濾的常用操作符。

bounce() 事件流只發射規定範圍時間內的數據項
distinct() 事件流只發射不重複的數據項
elementAt() 事件流只發射第N個數據項
filter() 事件流只發射符合規定函數的數據項
first() 事件流只發射第一個數據項
last() 事件流只發射最後一項數據項
ignoreElements() 忽略事件流的發射,只發射事件流的終止事件
sample() 事件流對指定的時間間隔進行數據項的採樣
skip() 事件流忽略前N個數據項
skipLast() 事件流忽略後N個數據項
take() 事件流只發射前N個數據項
takeLast() 事件流只發射後N個數據項

3.1 skip / skipLast

可以作用於Flowable,Observable,表示源發射數據前,跳過多少個。skipLast(n)操作表示從流的尾部跳過n個元素。

Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
source.skipLast(4)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.w("TAG","onNext--->"+ integer);
                    }
                });
// 結果:1 2 3 4 5 6

//Lambda寫法
Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
source.skip(4)
                .subscribe(i->{
                    Log.w("TAG","onNext--->"+ i);
                });
// 結果:5 6 7 8 9 10

3.2 debounce(去抖動)

可作用於Flowable,Observable。在Android開發,通常爲了防止用戶重複點擊而設置標記位,而通過RxJava的debounce操作符可以有效達到該效果。在規定時間內,用戶重複點擊只有最後一次有效,

        Observable<String> source = Observable.create(emitter -> {
            emitter.onNext("A");

            Thread.sleep(1_500);
            emitter.onNext("B");

            Thread.sleep(500);
            emitter.onNext("C");

            Thread.sleep(250);
            emitter.onNext("D");

            Thread.sleep(2000);
            emitter.onNext("E");
            emitter.onComplete();
        });

        source.subscribeOn(Schedulers.io())
                .debounce(1, TimeUnit.SECONDS)
                .blockingSubscribe(
                        item ->   Log.w("TAG","onNext--->"+ item),
                        Throwable::printStackTrace,
                        () -> Log.w("TAG","onNext--->"+ "onComplete" ));

//結果
2020-04-03 16:08:47.520 30559-30559/com.ysalliance.getfan.myapplication W/TAG: onNext--->A
2020-04-03 16:08:49.777 30559-30559/com.ysalliance.getfan.myapplication W/TAG: onNext--->D
2020-04-03 16:08:50.776 30559-30559/com.ysalliance.getfan.myapplication W/TAG: onNext--->E
2020-04-03 16:08:50.776 30559-30559/com.ysalliance.getfan.myapplication W/TAG: onNext--->onComplete

上文代碼中,數據源以一定的時間間隔發送A,B,C,D,E。操作符debounce的時間設爲1秒,發送A後1.5秒並沒有發射其他數據,所以A能成功發射。發射B後,在1秒之內,又發射了C和D,在D之後的2秒才發射E,所有B、C都失效,只有D有效;而E之後已經沒有其他數據流了,所有E有效。

3.3 distinct(去重)

可作用於Flowable,Observable,去掉數據源重複的數據。

distinctUntilChanged()去掉相鄰重複數據。

Observable.just(2, 3, 4, 4, 2, 1)
        .distinct()
        .subscribe(System.out::print);

// 打印:2 3 4 1
Observable.just(1, 1, 2, 1, 2, 3, 3, 4)
        .distinctUntilChanged()
        .subscribe(System.out::print);
//打印:1 2 1 2 3 4

3.4 elementAt(獲取指定位置元素)

可作用於Flowable,Observable,從數據源獲取指定位置的元素,從0開始。

elementAtOrError:指定元素的位置超過數據長度,則發射異常。

 Observable.just(2,4,3,1,5,8)
        .elementAt(0)
        .subscribe(integer -> 
         Log.d("TAG","elmentAt->"+integer));
打印:2

Observable<String> source = Observable.just("Kirk", "Spock", "Chekov", "Sulu");
Single<String> element = source.elementAtOrError(4);

element.subscribe(
    name -> System.out.println("onSuccess will not be printed!"),
    error -> System.out.println("onError: " + error));
打印:onSuccess will not be printed!

3.5 filter(過濾)

可作用於 Flowable,Observable,Maybe,Single。在filter中返回表示發射該元素,返回false表示過濾該數據。

Observable.just(1, 2, 3, 4, 5, 6)
        .filter(x -> x % 2 == 0)
        .subscribe(System.out::print);
打印:2 4 6

3.6 first(第一個)

作用於 Flowable,Observable。發射數據源第一個數據,如果沒有則發送默認值。

Observable<String> source = Observable.just("A", "B", "C");
Single<String> firstOrDefault = source.first("D");
firstOrDefault.subscribe(System.out::println);
打印:A

Observable<String> emptySource = Observable.empty();
Single<String> firstOrError = emptySource.firstOrError();
firstOrError.subscribe(
        element -> System.out.println("onSuccess will not be printed!"),
        error -> System.out.println("onError: " + error));
打印:onError: java.util.NoSuchElementException

和firstElement的區別是first返回的是Single,而firstElement返回Maybe。firstOrError在沒有數據會返回異常。

3.7 last(最後一個)

last、lastElement、lastOrError與fist、firstElement、firstOrError相對應。

Observable<String> source = Observable.just("A", "B", "C");
Single<String> lastOrDefault = source.last("D");
lastOrDefault.subscribe(System.out::println);
//打印:C

Observable<String> source = Observable.just("A", "B", "C");
Maybe<String> last = source.lastElement();
last.subscribe(System.out::println);
//打印:C

Observable<String> emptySource = Observable.empty();
Single<String> lastOrError = emptySource.lastOrError();
lastOrError.subscribe(
        element -> System.out.println("onSuccess will not be printed!"),
        error -> System.out.println("onError: " + error));
// 打印:onError: java.util.NoSuchElementException

3.8 ignoreElements & ignoreElement(忽略元素)

ignoreElements 作用於Flowable、Observable。ignoreElement作用於Maybe、Single。兩者都是忽略掉數據,不發射任何數據,返回完成或者錯誤時間。

這裏關注下intervalRange的用法,以下面這個例子說明:從1開始輸出5個數據,延遲1秒執行,每隔1秒執行一次:

Single<Long> source = Single.timer(1, TimeUnit.SECONDS);
Completable completable = source.ignoreElement();
completable.doOnComplete(() -> System.out.println("Done!"))
        .blockingAwait();
// 1秒後打印:Donde!

Observable<Long> source = Observable.intervalRange(1, 5, 1, 1, TimeUnit.SECONDS);
Completable completable = source.ignoreElements();
completable.doOnComplete(() -> System.out.println("Done!"))
        .blockingAwait();
// 六秒後打印:Done!

3.9 ofType(過濾類型)

作用於Flowable、Observable、Maybe,過濾選擇類型。

Observable<Number> numbers = Observable.just(1, 4.0, 3, 2.71, 2f, 7);
Observable<Integer> integers = numbers.ofType(Integer.class);
integers.subscribe((Integer x) -> System.out.print(x+" "));
//打印:1 3 7

3.10 sample

作用於Flowable、Observable,在一個週期內發射最新的數據。sample操作符會在指定的事件內從數據項中採集所需要的數據。

Observable<String> source = Observable.create(emitter -> {
    emitter.onNext("A");

    Thread.sleep(500);
    emitter.onNext("B");

    Thread.sleep(200);
    emitter.onNext("C");

    Thread.sleep(800);
    emitter.onNext("D");

    Thread.sleep(600);
    emitter.onNext("E");
    emitter.onComplete();
});

source.subscribeOn(Schedulers.io())
        .sample(1, TimeUnit.SECONDS)
        .blockingSubscribe(
                item -> System.out.print(item+" "),
                Throwable::printStackTrace,
                () -> System.out.print("onComplete"));
                
// 打印: C D onComplete

與debounce的區別是,sample是以時間爲週期的發射,一秒又一秒內的最新數據。而debounce是最後一個有效數據開始。

3.11 throttleFirst & throttleLast & throttleWithTimeout & throttleLatest

作用於Flowable、Observable。throttleFirst是指定週期內第一個數據,throttleLast與smaple一致。throttleWithTimeout與debounce一致。

Observable<String> source = Observable.create(emitter -> {
    emitter.onNext("A");

    Thread.sleep(500);
    emitter.onNext("B");

    Thread.sleep(200);
    emitter.onNext("C");

    Thread.sleep(800);
    emitter.onNext("D");

    Thread.sleep(600);
    emitter.onNext("E");
    emitter.onComplete();
});

source.subscribeOn(Schedulers.io())
        .throttleFirst(1, TimeUnit.SECONDS)
        .blockingSubscribe(
                item -> System.out.print(item+" "),
                Throwable::printStackTrace,
                () -> System.out.print(" onComplete"));
//打印:A D onComplete

source.subscribeOn(Schedulers.io())
        .throttleLast(1, TimeUnit.SECONDS)
        .blockingSubscribe(
                item -> System.out.print(item+" "),
                Throwable::printStackTrace,
                () -> System.out.print(" onComplete"));

// 打印:C D onComplete

throttleLatest:如果源的第一個數據總會被髮射,然後開始週期計時,此時的效果就會跟throttleLast一致。

Observable<String> source = Observable.create(emitter -> {
            emitter.onNext("A");

            Thread.sleep(500);
            emitter.onNext("B");

            Thread.sleep(200);
            emitter.onNext("C");

            Thread.sleep(200);
            emitter.onNext("D");

            Thread.sleep(400);
            emitter.onNext("E");
            
            Thread.sleep(400);
            emitter.onNext("F");
            
            Thread.sleep(400);
            emitter.onNext("G");
            
            Thread.sleep(2000);
            emitter.onComplete();
        });
        source.subscribeOn(Schedulers.io())
        .throttleLatest(1, TimeUnit.SECONDS)
        .blockingSubscribe(
            item -> Log.e("RxJava",item),
                 Throwable::printStackTrace,
            () -> Log.e("RxJava","finished"));

//打印 A D F G RxJava","finished

3.12 take & takeLast

作用於Flowable、Observable。take發射前n個元素。takeLast發射後n個元素。

Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

source.take(4)
    .subscribe(System.out::print);
//打印:1 2 3 4

source.takeLast(4)
    .subscribe(System.out::println);
//打印:7 8 9 10

3.13 timeout(超時)

作用於Flowable、Observable、Maybe、Single、Completabl。後一個數據發射未在前一個元素髮射後規定時間內發射則返回超時異常。

Observable<String> source = Observable.create(emitter -> {
    emitter.onNext("A");

    Thread.sleep(800);
    emitter.onNext("B");

    Thread.sleep(400);
    emitter.onNext("C");

    Thread.sleep(1200);
    emitter.onNext("D");
    emitter.onComplete();
});

source.timeout(1, TimeUnit.SECONDS)
        .subscribe(
                item -> System.out.println("onNext: " + item),
                error -> System.out.println("onError: " + error),
                () -> System.out.println("onComplete will not be printed!"));
// 打印:
// onNext: A
// onNext: B
// onNext: C
// onError: java.util.concurrent.TimeoutException: 
            The source did not signal an event for 1 seconds 
            and has been terminated.

 3.14 merge/concat

merge操作符可以合併兩個事件流,如果在merge操作符上增加延時發送的操作,那麼就會導致其發射的數據項是無序的,會跟着發射的時間點進行合併。雖然是將兩個事件流合併成一個事件流進行發射,但在最終的一個事件流中,發射出來的卻是兩次數據流。

merge和concat的區別:merge():合併後發射的數據項是無序的​​​​​​,concat():合併後發射的數據項是有序的。

        Observable<String> just1 = Observable.just("A", "B", "C");
        Observable<String> just2 = Observable.just("1", "2", "3");

        Observable.merge(just1, just2).subscribe(new Consumer<Serializable>() {
            @Override
            public void accept(Serializable serializable) throws Exception {
                Log.i("lucas", "" + serializable.toString() );
            }
        });
//打印結果
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: A
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: B
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: C
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: 1
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 17:52:20.734 4372-4372/com.ysalliance.getfan.myapplication I/lucas: 3

 3.15 zip()

zip操作符是將兩個數據流進行指定的函數規則合併。

        Observable<String> just1 = Observable.just("A", "B", "C");
        Observable<String> just2 = Observable.just("1", "2", "3");

        Observable.zip(just1, just2, new BiFunction<String, String, String>() {
            @Override
            public String apply(String s, String s2) throws Exception {
                return s + s2;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("lucas", "" + s );
            }
        });
//打印結果
2020-04-04 17:55:08.905 4744-4744/com.ysalliance.getfan.myapplication I/lucas: A1
2020-04-04 17:55:08.905 4744-4744/com.ysalliance.getfan.myapplication I/lucas: B2
2020-04-04 17:55:08.905 4744-4744/com.ysalliance.getfan.myapplication I/lucas: C3

 3.16 startWith()

startWith操作符是將另一個數據流合併到原數據流的開頭。

        Observable<String> just1 = Observable.just("A", "B", "C");
        Observable<String> just2 = Observable.just("1", "2", "3");

        just1.startWith(just2).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("lucas", "" + s );
            }
        });
//打印結果
2020-04-04 17:57:22.155 4917-4917/com.ysalliance.getfan.myapplication I/lucas: 1
2020-04-04 17:57:22.155 4917-4917/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 17:57:22.156 4917-4917/com.ysalliance.getfan.myapplication I/lucas: 3
2020-04-04 17:57:22.156 4917-4917/com.ysalliance.getfan.myapplication I/lucas: A
2020-04-04 17:57:22.156 4917-4917/com.ysalliance.getfan.myapplication I/lucas: B
2020-04-04 17:57:22.156 4917-4917/com.ysalliance.getfan.myapplication I/lucas: C

 3.17 join()

join操作符是有時間期限的合併操作符。

        Observable<String> just1 = Observable.just("A", "B", "C");
        Observable<Long> just2 = Observable.interval(1, TimeUnit.SECONDS);

        just1.join(just2, new Function<String, ObservableSource<Long>>() {
            @Override
            public ObservableSource<Long> apply(String s) throws Exception {
                return Observable.timer(3, TimeUnit.SECONDS);
            }
        }, new Function<Long, ObservableSource<Long>>() {
            @Override
            public ObservableSource<Long> apply(Long l) throws Exception {
                return Observable.timer(8, TimeUnit.SECONDS);
            }
        }, new BiFunction<String, Long, String>() {
            @Override
            public String apply(String s, Long l) throws Exception {
                return s + l;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("lucas", "" + s );
            }
        });

//打印結果
2020-04-04 18:04:43.751 6042-6109/com.ysalliance.getfan.myapplication I/lucas: A0
2020-04-04 18:04:43.752 6042-6109/com.ysalliance.getfan.myapplication I/lucas: B0
2020-04-04 18:04:43.752 6042-6109/com.ysalliance.getfan.myapplication I/lucas: C0
2020-04-04 18:04:44.750 6042-6109/com.ysalliance.getfan.myapplication I/lucas: A1
2020-04-04 18:04:44.751 6042-6109/com.ysalliance.getfan.myapplication I/lucas: B1
2020-04-04 18:04:44.751 6042-6109/com.ysalliance.getfan.myapplication I/lucas: C1

join操作符有三個函數需要設置

第一個函數:規定just2的過期期限
第二個函數:規定just1的過期期限
第三個函數:規定just1和just2的合併規則
由於just2的期限只有3秒的時間,而just2延時1秒發送一次,所以just2只發射了2次,其輸出的結果就只能和just2輸出的兩次進行合併,其輸出格式有點類似我們的排列組合。


4 連接/組合操作符

通過連接操作符,可以將多個被觀察數據(數據源)連接在一起。

4.1 startWith()

可作用於Flowable、Observable。將指定數據源合併在另外數據源的開頭。

Observable<String> name = Observable.just("My", "name");
Observable<String> name2 = Observable.just("is", "Lucas","!");
name2.startWith(name).subscribe(item -> Log.d("Lucas",item));

//打印:
2020-04-03 16:35:49.493 31609-31609/com.ysalliance.getfan.myapplication D/Lucas: My
2020-04-03 16:35:49.493 31609-31609/com.ysalliance.getfan.myapplication D/Lucas: name
2020-04-03 16:35:49.493 31609-31609/com.ysalliance.getfan.myapplication D/Lucas: is
2020-04-03 16:35:49.493 31609-31609/com.ysalliance.getfan.myapplication D/Lucas: Lucas
2020-04-03 16:35:49.493 31609-31609/com.ysalliance.getfan.myapplication D/Lucas: !

4.2 merge / mergeWith

可作用所有數據源類型,用於合併多個數據源到一個數據源。

        Observable<String> name = Observable.just("My", "name");
        Observable<String> name2 = Observable.just("is", "Lucas","!");

        Observable.merge(name,name2).subscribe(v -> Log.d("lucas", v));
        name.mergeWith(name2).subscribe(v -> Log.d("lucas",v));
//打印:
2020-04-03 16:39:41.934 32212-32212/com.ysalliance.getfan.myapplication D/lucas: My
2020-04-03 16:39:41.934 32212-32212/com.ysalliance.getfan.myapplication D/lucas: name
2020-04-03 16:39:41.934 32212-32212/com.ysalliance.getfan.myapplication D/lucas: is
2020-04-03 16:39:41.935 32212-32212/com.ysalliance.getfan.myapplication D/lucas: Lucas
2020-04-03 16:39:41.935 32212-32212/com.ysalliance.getfan.myapplication D/lucas: !
2020-04-03 16:39:41.937 32212-32212/com.ysalliance.getfan.myapplication D/lucas: My
2020-04-03 16:39:41.937 32212-32212/com.ysalliance.getfan.myapplication D/lucas: name
2020-04-03 16:39:41.937 32212-32212/com.ysalliance.getfan.myapplication D/lucas: is
2020-04-03 16:39:41.937 32212-32212/com.ysalliance.getfan.myapplication D/lucas: Lucas
2020-04-03 16:39:41.937 32212-32212/com.ysalliance.getfan.myapplication D/lucas: !

merge在合併數據源時,如果一個合併發生異常後會立即調用觀察者的onError方法,並停止合併。可通過mergeDelayError操作符,將發生的異常留到最後處理。

        Observable<String> name = Observable.just("My", "name");
        Observable<String> name2 = Observable.just("is", "Lucas","!");
        Observable<String> error = Observable.error(new NullPointerException("Error!"));

        Observable.mergeDelayError(name,error,name2).subscribe(
                v -> Log.d("lucas",v), e->Log.d("lucas",e.getMessage()));
    
//打印:
2020-04-03 16:42:07.030 32391-32391/com.ysalliance.getfan.myapplication D/lucas: My
2020-04-03 16:42:07.030 32391-32391/com.ysalliance.getfan.myapplication D/lucas: name
2020-04-03 16:42:07.033 32391-32391/com.ysalliance.getfan.myapplication D/lucas: is
2020-04-03 16:42:07.034 32391-32391/com.ysalliance.getfan.myapplication D/lucas: Lucas
2020-04-03 16:42:07.034 32391-32391/com.ysalliance.getfan.myapplication D/lucas: !
2020-04-03 16:42:07.034 32391-32391/com.ysalliance.getfan.myapplication D/lucas: Error!

4.3 zip()

可作用於Flowable、Observable、Maybe、Single。將多個數據源的數據一個一個的合併在一起哇。當其中一個數據源發射完事件之後,若其他數據源還有數據未發射完畢,也會停止。

        Observable<String> name = Observable.just("My", "name");
        Observable<String> name2 = Observable.just("is", "Lucas", "!", "haha!");
        name.zipWith(name2, (first, last) -> first + "-" + last)
                .subscribe(item -> Log.d("lucas", item));

//打印:
2020-04-03 16:44:59.127 32616-32616/com.ysalliance.getfan.myapplication D/lucas: My-is
2020-04-03 16:44:59.128 32616-32616/com.ysalliance.getfan.myapplication D/lucas: name-Lucas

4.4 combineLatest()

public static String[] str = {"A", "B", "C", "D", "E"};

public void combineLatest() {
    Observable<String> just1 = Observable.interval(1, TimeUnit.SECONDS).map(new Function<Long, String>() {
        @Override
        public String apply(Long aLong) throws Exception {
            return str[(int) (aLong % 5)];
        }
    });
    Observable<Long> just2 = Observable.interval(1, TimeUnit.SECONDS);

    Observable.combineLatest(just1, just2, new BiFunction<String, Long, String>() {
        @Override
        public String apply(String s, Long l) throws Exception {
            return s + l;
        }
    }).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            System.out.println("onNext=" + s);
        }
    });
}

//輸出
onNext=A0
onNext=B0
onNext=B1
onNext=C1
onNext=C2
onNext=D2
onNext=D3
onNext=E3
onNext=E4
onNext=A4
onNext=A5

可作用於Flowable, Observable。在結合不同數據源時,發射速度快的數據源最新item與較慢的相結合。 如下時間線,Observable-1發射速率快,發射了65,Observable-2才發射了C, 那麼兩者結合就是C5。

4.5 switchOnNext()

一個發射多個小數據源的數據源,這些小數據源發射數據的時間發生重複時,取最新的數據源。


5 變換/轉換操作符

變換操作符用於變化數據源的數據,並轉化爲新的數據源。

map() 對數據流的類型進行轉換
flatMap() 對數據流的類型進行包裝成另一個數據流
scan() 對上一輪處理過後的數據流進行函數處理
groupBy() 對所有的數據流進行分組
buffer() 緩存發射的數據流到一定數量,隨後發射出數據流集合
window() 緩存發射的數據流到一定數量,隨後發射出新的事件流

5.1 map()

map利用Function進行類型轉換的例子:

        Observable.just("1", "2", "3").map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) throws Exception {
                return Integer.valueOf(s) * 100;
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.i("lucas", ""+integer);
            }
        });

在實際編碼中,我們還是常用Lambda表達式進行代碼的精簡優化,但是掌握Lambda的前提是,你還得會寫非Lambda的表達,否則長時間下來可能會忘記原來的類寫法:

Observable.just("1", "2", "3")
                .map( (String s) -> Integer.valueOf(s) * 100)
                .subscribe(integer -> Log.i("lucas", ""+integer));

可以看到,使用Lambda表達式後只有三行,簡潔!

5.2 flatMap() / concatMap()

flatMap操作符將數據流進行類型轉換,然後將新的數據流傳遞給新的事件流進行分發,這裏通過模擬請求登錄的延時操作進行說明

public static class UserParams {

    public UserParams(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String username;
    public String password;
}

        

Observable.just(new UserParams("lucas", "123123")).flatMap(new Function<UserParams, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(UserParams userParams) throws Exception {
                return Observable.just(userParams.username + "登錄成功").delay(2, TimeUnit.SECONDS);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.i("lucas", "" + s );
            }
        });

Lambda表達式優化:

      Observable.just(new UserParams("lucas", "123123"))
                .flatMap((UserParams userParams)->Observable.just(userParams.username + "登錄成功")
                .delay(2, TimeUnit.SECONDS))
                .subscribe(s -> Log.i("lucas", "" + s ));

concatMap與flatMap的區別:    concatMap是有序的,flatMap是無序的。

再舉個組合的例子:

        Observable.just("A", "B", "C")
                .flatMap(a -> {
                    return Observable.intervalRange(1, 3, 0, 1, TimeUnit.SECONDS)
                            .map(b -> '(' + a + ", " + b + ')');
                })
                .blockingSubscribe( v -> {
                    Log.d("lucas",  v+" "  );
                });

//打印結果
2020-04-03 22:05:58.363 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (A, 1) 
2020-04-03 22:05:58.365 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (B, 1) 
2020-04-03 22:05:58.367 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (C, 1) 
2020-04-03 22:05:59.355 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (A, 2) 
2020-04-03 22:05:59.362 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (B, 2) 
2020-04-03 22:05:59.362 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (C, 2) 
2020-04-03 22:06:00.357 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (A, 3) 
2020-04-03 22:06:00.361 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (B, 3) 
2020-04-03 22:06:00.363 12414-12414/com.ysalliance.getfan.myapplication D/lucas: (C, 3) 

5.3 groupBy()

groupBy操作符可以將發射出來的數據項進行分組,並將分組後的數據項保存在具有key-value映射的事件流中。groupBy具體的分組規則由groupBy操作符傳遞進來的函數參數Function所決定的,它可以將key和value按照Function的返回值進行分組,返回一個具有分組規則的事件流GroupedObservable,注意這裏分組出來的事件流是按照原始事件流的順序輸出的,我們可以通過sorted()對數據項進行排序,然後輸出有序的數據流。

        Observable.just("java", "c", "c++", "python", "javaScript", "android")
                .groupBy(new Function<String, Character>() {
                    @Override
                    public Character apply(String s) throws Exception {
                        return s.charAt(0);//按首字母分組
                    }
                })
                .subscribe(new Consumer<GroupedObservable<Character, String>>() {
                    @Override
                    public void accept(final GroupedObservable<Character, String> characterStringGroupedObservable) throws Exception {
                        //排序後,直接訂閱輸出key和value
                        characterStringGroupedObservable.sorted().subscribe(new Consumer<String>() {
                            @Override
                            public void accept(String s) throws Exception {
                                Log.i("lucas", "onNext= key:" + characterStringGroupedObservable.getKey() + " value:" + s);
                            }
                        });
                    }
                });

//打印結果
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:p value:python
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:a value:android
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:c value:c
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:c value:c++
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:j value:java
2020-04-04 16:36:13.766 32460-32460/com.ysalliance.getfan.myapplication I/lucas: onNext= key:j value:javaScript
Observable<String> animals = Observable.just(
    "Tiger", "Elephant", "Cat", "Chameleon", "Frog", "Fish", "Turtle", "Flamingo");

animals.groupBy(animal -> animal.charAt(0), String::toUpperCase)
    .concatMapSingle(Observable::toList)
    .subscribe(System.out::println);

// prints:
// [TIGER, TURTLE]
// [ELEPHANT]
// [CAT, CHAMELEON]
// [FROG, FISH, FLAMINGO]

5.4 scan()

scan操作符會對發射的數據和上一輪發射的數據進行函數處理,並返回的數據供下一輪使用,持續這個過程來產生剩餘的數據流。其應用場景有簡單的累加計算,判斷所有數據的最小值等。

        Observable.just(2, 4, 1, 9).scan(new BiFunction<Integer, Integer, Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) throws Exception {
                return integer < integer2 ? integer : integer2;
            }
        })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer item) throws Exception {
                        Log.i("lucas", "" + item );
                    }
                });

//打印結果
2020-04-04 16:14:10.931 30301-30301/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 16:14:10.931 30301-30301/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 16:14:10.931 30301-30301/com.ysalliance.getfan.myapplication I/lucas: 1
2020-04-04 16:14:10.931 30301-30301/com.ysalliance.getfan.myapplication I/lucas: 1

Lambda表達式寫法:

        Observable.just(2, 4, 1, 9)
                .scan((Integer integer, Integer integer2) -> integer < integer2 ? integer : integer2)
                .subscribe(item -> Log.i("lucas", "" + item ));

帶初始值的聚合疊加:

        Observable.just(1, 2, 3)
                .scan(10, (x, y) -> x + y)
                .subscribe(item -> Log.i("lucas", "" + item ));

// prints:
2020-04-04 16:23:06.590 31451-31451/com.ysalliance.getfan.myapplication I/lucas: 10
2020-04-04 16:23:06.590 31451-31451/com.ysalliance.getfan.myapplication I/lucas: 11
2020-04-04 16:23:06.590 31451-31451/com.ysalliance.getfan.myapplication I/lucas: 13
2020-04-04 16:23:06.590 31451-31451/com.ysalliance.getfan.myapplication I/lucas: 16

5.5 buffer()

buffer操作符可以將發射出來的數據流,在給定的緩存池中進行緩存,當緩存池中的數據項溢滿時,則將緩存池的數據項進行輸出,重複上述過程,直到將發射出來的數據全部發射出去。如果發射出來的數據不夠緩存池的大小,則按照當前發射出來的數量進行輸出。如果對buffer操作符設置了skip參數,則buffer每次緩存池溢滿時,會跳過指定的skip數據項,然後再進行緩存和輸出。

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8)
                .buffer(3).subscribe(new Consumer<List<Integer>>() {
            @Override
            public void accept(List<Integer> integers) throws Exception {
                Log.i("lucas", "" + integers.toString() );
            }
        });
//打印結果
2020-04-04 16:40:41.744 32722-32722/com.ysalliance.getfan.myapplication I/lucas: [1, 2, 3]
2020-04-04 16:40:41.745 32722-32722/com.ysalliance.getfan.myapplication I/lucas: [4, 5, 6]
2020-04-04 16:40:41.745 32722-32722/com.ysalliance.getfan.myapplication I/lucas: [7, 8]

5.6 window()

window操作符和buffer操作符在功能上實現的效果是一樣的,但window操作符最大區別在於同樣是緩存一定數量的數據項,window操作符最終發射出來的是新的事件流integerObservable,而buffer操作符發射出來的是新的數據流,也就是說,window操作符發射出來新的事件流中的數據項,還可以經過Rxjava其他操作符進行處理。

        Observable.just(1, 2, 3, 4)
                .window(2, 1).subscribe(new Consumer<Observable<Integer>>() {
            @Override
            public void accept(Observable<Integer> integerObservable) throws Exception {
                integerObservable.subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.i("lucas", "" + integer );
                    }
                });
            }
        });

//打印結果
2020-04-04 16:49:54.681 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 1
2020-04-04 16:49:54.681 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 16:49:54.682 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 2
2020-04-04 16:49:54.682 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 3
2020-04-04 16:49:54.682 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 3
2020-04-04 16:49:54.682 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 4
2020-04-04 16:49:54.682 1475-1475/com.ysalliance.getfan.myapplication I/lucas: 4
Observable.range(1, 4)
    // Create windows containing at most 2 items, and skip 3 items before starting a new window.
    .window(2)
    .flatMapSingle(window -> {
        return window.map(String::valueOf)
                .reduce(new StringJoiner(", ", "[", "]"), StringJoiner::add);
    })
    .subscribe(System.out::println);

// prints:
// [1, 2]
// [3, 4]

5.7 cast()

作用於Flowable、Observable、Maybe、Single。將數據元素轉型成其他類型,轉型失敗會拋出異常。

Observable<Number> numbers = Observable.just(1, 4.0, 3f, 7, 12, 4.6, 5);

numbers.filter((Number x) -> Integer.class.isInstance(x))
    .cast(Integer.class)
    .subscribe((Integer x) -> System.out.println(x));

// 打印:
// 1
// 7
// 12
// 5

5.8 concatMapDelayError

與concatMap作用相同,只是將過程發送的所有錯誤延遲到最後處理。

Observable.intervalRange(1, 3, 0, 1, TimeUnit.SECONDS)
    .concatMapDelayError(x -> {
        if (x.equals(1L)) return Observable.error(new IOException("Something went wrong!"));
        else return Observable.just(x, x * x);
    })
    .blockingSubscribe(
        x -> System.out.println("onNext: " + x),
        error -> System.out.println("onError: " + error.getMessage()));

// prints:
// onNext: 2
// onNext: 4
// onNext: 3
// onNext: 9
// onError: Something went wrong!

5.9 concatMapCompletable()

作用於Flowable、Observable。與contactMap類似,不過應用於函數後,返回的是CompletableSource。訂閱一次並在所有CompletableSource對象完成時返回一個Completable對象。

Observable<Integer> source = Observable.just(2, 1, 3);
Completable completable = source.concatMapCompletable(x -> {
    return Completable.timer(x, TimeUnit.SECONDS)
        .doOnComplete(() -> System.out.println("Info: Processing of item \"" + x + "\" completed"));
    });

completable.doOnComplete(() -> System.out.println("Info: Processing of all items completed"))
    .blockingAwait();

// prints:
// Info: Processing of item "2" completed
// Info: Processing of item "1" completed
// Info: Processing of item "3" completed
// Info: Processing of all items completed

5.10 concatMapCompletableDelayError()

與concatMapCompletable作用相同,只是將過程發送的所有錯誤延遲到最後處理。

Observable<Integer> source = Observable.just(2, 1, 3);
Completable completable = source.concatMapCompletableDelayError(x -> {
    if (x.equals(2)) {
        return Completable.error(new IOException("Processing of item \"" + x + "\" failed!"));
    } else {
        return Completable.timer(1, TimeUnit.SECONDS)
            .doOnComplete(() -> System.out.println("Info: Processing of item \"" + x + "\" completed"));
    }
});

completable.doOnError(error -> System.out.println("Error: " + error.getMessage()))
    .onErrorComplete()
    .blockingAwait();

// prints:
// Info: Processing of item "1" completed
// Info: Processing of item "3" completed
// Error: Processing of item "2" failed!

5.11 flattenAsFlowable & flattenAsObservable

作用於Maybe、Single,將其轉化爲Flowable,或Observable。

Single<Double> source = Single.just(2.0);
Flowable<Double> flowable = source.flattenAsFlowable(x -> {
    return List.of(x, Math.pow(x, 2), Math.pow(x, 3));
});

flowable.subscribe(x -> System.out.println("onNext: " + x));

// prints:
// onNext: 2.0
// onNext: 4.0
// onNext: 8.0

 


6 處理操作符

onErrorReturn() 當錯誤發生時,它會忽略onError的回調且會發射一個新的數據項並回調onCompleted()
onErrorResumeNext() 當錯誤發生時,它會忽略onError的回調且會發射一個新的事件流並回調onCompleted()
onExceptionResumeNext() 當錯誤發生時,如果onError收到的Throwable不是一個Exception,它會回調onError方法,且不會回調備用的事件流,如果onError收到的Throwable是一個Exception,它會回調備用的事件流進行數據的發射
retry() 當錯誤發生時,發射器會重新發射
retryWhen() 當錯誤發生時,根據Tharowble類型決定發射器是否重新發射

6.1 onErrorReturn()

作用於Flowable、Observable、Maybe、Single。但調用數據源的onError函數後會回到該函數,可對錯誤進行處理,然後返回值,會調用觀察者onNext()繼續執行,執行完調用onComplete()函數結束所有事件的發射。

        Single.just("2A")
                .map(v -> Integer.parseInt(v, 10))
                .onErrorReturn(error -> {
                    if (error instanceof NumberFormatException) return 0;
                    else throw new IllegalArgumentException();
                })
                .subscribe(
                        v->Log.d("lucas",  v+" "  ),
                        error -> System.err.println("onError should not be printed!"));

// 
2020-04-03 22:13:56.573 13238-13238/com.ysalliance.getfan.myapplication D/lucas: 0 

6.2 onErrorReturnItem()

與onErrorReturn類似,onErrorReturnItem不對錯誤進行處理,直接返回一個值。

        Single.just("2A")
                .map(v -> Integer.parseInt(v, 10))
                .onErrorReturnItem(0)
                .subscribe(
                        v->Log.d("lucas",  v+" "  ),
                        error -> System.err.println("onError should not be printed!"));

// 
2020-04-03 22:12:53.757 13100-13100/com.ysalliance.getfan.myapplication D/lucas: 0 

6.3 onExceptionResumeNext()

可作用於Flowable、Observable、Maybe。

onErrorReturn發生異常時,回調onComplete()函數後不再往下執行,而onExceptionResumeNext則是要在處理異常的時候返回一個數據源,然後繼續執行,如果返回null,則調用觀察者的onError()函數。


        Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onNext(3);
            e.onError(new NullPointerException());
            e.onNext(4);
        })
                .onErrorResumeNext(throwable -> {
                    Log.d("lucas", "onErrorResumeNext ");
                    return Observable.just(4);
                })
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d("lucas", "onSubscribe ");
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.d("lucas", "onNext " + integer);
                    }

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

                    @Override
                    public void onComplete() {
                        Log.d("lucas", "onComplete ");
                    }
                });


//運行結果
2020-04-03 22:15:58.668 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onSubscribe 
2020-04-03 22:15:58.672 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onNext 1
2020-04-03 22:15:58.672 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onNext 2
2020-04-03 22:15:58.673 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onNext 3
2020-04-03 22:15:58.673 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onErrorResumeNext 
2020-04-03 22:15:58.674 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onNext 4
2020-04-03 22:15:58.674 13456-13456/com.ysalliance.getfan.myapplication D/lucas: onComplete 

6.4 retry()

可作用於所有的數據源,當發生錯誤時,數據源重複發射item,直到沒有異常或者達到所指定的次數。

     Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);

            if (first){
                first=false;
                e.onError(new NullPointerException());

            }

        })
                .retry(9)
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d("lucas", "onSubscribe ");
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.d("lucas", "onNext " + integer);

                    }

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

                    @Override
                    public void onComplete() {
                        Log.d("lucas", "onComplete ");
                    }
                });

//打印結果
2020-04-03 22:18:28.605 13647-13647/com.ysalliance.getfan.myapplication D/lucas: onSubscribe 
2020-04-03 22:18:28.607 13647-13647/com.ysalliance.getfan.myapplication D/lucas: onNext 1
2020-04-03 22:18:28.607 13647-13647/com.ysalliance.getfan.myapplication D/lucas: onNext 2
2020-04-03 22:18:28.607 13647-13647/com.ysalliance.getfan.myapplication D/lucas: onNext 1
2020-04-03 22:18:28.607 13647-13647/com.ysalliance.getfan.myapplication D/lucas: onNext 2
  • retry():表示重試無限次
  • retry(long times):表示重試指定次數
  • retry(Func predicate):可以根據函數參數中的Throwable類型和重試次數決定本次需不需要重試

6.5 retryUntil()

作用於Flowable、Observable、Maybe。與retry類似,但發生異常時,返回值是false表示繼續執行(重複發射數據),true不再執行,但會調用onError方法。

        Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onError(new NullPointerException());
            e.onNext(3);
            e.onComplete();
        })
                .retryUntil(() -> true)
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d("lucas", "onSubscribe ");
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.d("lucas", "onNext " + integer);

                    }

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

                    @Override
                    public void onComplete() {
                        Log.d("lucas", "onComplete ");
                    }
                });

//打印結果
2020-04-03 22:22:01.625 13905-13905/com.ysalliance.getfan.myapplication D/lucas: onSubscribe 
2020-04-03 22:22:01.627 13905-13905/com.ysalliance.getfan.myapplication D/lucas: onNext 1
2020-04-03 22:22:01.627 13905-13905/com.ysalliance.getfan.myapplication D/lucas: onNext 2
2020-04-03 22:22:01.627 13905-13905/com.ysalliance.getfan.myapplication D/lucas: onError 

6.6  retryWhen()

retryWhen操作符和retry操作符相似,區別在於retryWhen將錯誤Throwable傳遞給了函數進行處理併產生新的事件流進行處理。

private static int retryCount = 0;
private static int maxRetries = 2;

public void retryWhen(){
    Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
            for (int i = 1; i < 5; i++) {
                if (i == 4) {
                    e.onError(new Exception("onError crash"));
                }
                e.onNext(i);
            }
        }
    })
            .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
                    return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                        @Override
                        public ObservableSource<?> apply(Throwable throwable) throws Exception {
                            if (++retryCount <= maxRetries) {
                                // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
                                System.out.println("get error, it will try after " + 1 + " seconds, retry count " + retryCount);
                                return Observable.timer(1, TimeUnit.SECONDS);
                            }
                            return Observable.error(throwable);
                        }
                    });
                }
            })
            .onErrorReturn(new Function<Throwable, Integer>() {
                @Override
                public Integer apply(Throwable throwable) throws Exception {
                    return -1;
                }
            })
            .subscribe(new Consumer<Integer>() {
                @Override
                public void accept(Integer integer) throws Exception {
                    System.out.println("onNext=" + integer);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    System.out.println("onError");
                }
            }, new Action() {

                @Override
                public void run() throws Exception {
                    System.out.println("onComplete");
                }
            });
}


//結果 
onNext=1
onNext=2
onNext=3
get error, it will try after 1 seconds, retry count 1
onNext=1
onNext=2
onNext=3
get error, it will try after 1 seconds, retry count 2
onNext=1
onNext=2
onNext=3
onNext=-1
onComplete

 

 

補充1:Rxjava3包結構的變動:

Rxjava3組件位於 io.reactivex.rxjava3包(rxjava1有 rx,rxjava2是 io.reactivex)。 這使得Rxjava3可以和早期版本一起使用。 此外,RxJava 的核心類型(Flowable、 Observer 等)已經被移動到 io.reactivex.rxjava3.core。

Component RxJava 2 RxJava 3
Core io.reactivex io.reactivex.rxjava3.core
Annotations io.reactivex.annotations io.reactivex.rxjava3.annotations
Disposables io.reactivex.disposables io.reactivex.rxjava3.disposables
Exceptions io.reactivex.exceptions io.reactivex.rxjava3.exceptions
Functions io.reactivex.functions io.reactivex.rxjava3.functions
Flowables io.reactivex.flowables io.reactivex.rxjava3.flowables
Observables io.reactivex.observables io.reactivex.rxjava3.observables
Subjects io.reactivex.subjects io.reactivex.rxjava3.subjects
Processors io.reactivex.processors io.reactivex.rxjava3.processors
Observers io.reactivex.observers io.reactivex.rxjava3.observers
Subscribers io.reactivex.subscribers io.reactivex.rxjava3.subscribers
Parallel io.reactivex.parallel io.reactivex.rxjava3.parallel
Internal io.reactivex.internal io.reactivex.rxjava3.internal

補充2:

在RxJava1.0中,有的人會使用CompositeSubscription來收集Subscription,來統一取消訂閱,現在在RxJava2.0中,由於subscribe()方法現在返回void,那怎麼辦呢?

其實在RxJava2.0中,Flowable提供了subscribeWith這個方法可以返回當前訂閱的觀察者,並且通過ResourceSubscriber DisposableSubscriber等觀察者來提供 Disposable的接口

所以,如果想要達成RxJava1.0的效果,現在應該是這樣做:

CompositeDisposable composite = new CompositeDisposable();

composite.add(Flowable.range(1, 8).subscribeWith(subscriber));

這個subscriber 應該是 ResourceSubscriber 或者 DisposableSubscriber 的實例。

 

 

參考文章:

因爲寫RxJava系列的文章時進行了很多閱讀和參考,因此不分一二三等,將全系列的參考引用統一如下:

RxJava3 Wiki:https://github.com/ReactiveX/RxJava/wiki

RxJava3官方github:https://github.com/ReactiveX/RxJava/wiki/What's-different-in-3.0

ReactiveX文檔中文翻譯:https://mcxiaoke.gitbooks.io/rxdocs/content/operators/Creating-Observables.html

single:http://reactivex.io/documentation/single.html

操作符系列講的很好的文章:https://blog.csdn.net/weixin_42046829/article/details/104836592

基礎介紹:https://blog.csdn.net/weixin_42046829/article/details/104833751

RxJava3的一些簡介:https://juejin.im/post/5d1eeffe6fb9a07f0870b4e8

觀察者被觀察者入門RxJava的一篇好文章:https://juejin.im/post/580103f20e3dd90057fc3e6d

關於背壓一個很好的介紹:https://juejin.im/post/582d413c8ac24700619cceed

RxLifecycle:https://github.com/trello/RxLifecycle

剛哥平臺的挺好很全:RxJava2 只看這一篇文章就夠了https://juejin.im/post/5b17560e6fb9a01e2862246f

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