RxJava Error Handling Operators

weixin_33850890發表於2016-10-04

RxJava Error Handling Operators

簡介

RxJava提供了一些操作函式去處理錯誤相關的情景,使用這些函式可以:

  • 吞掉這個錯誤,切換到一個備用的Observable繼續發射資料
  • 吞掉這個錯誤然後發射預設值
  • 吞掉這個錯誤並立即嘗試重啟這個Observable
  • 吞掉這個錯誤,在等待一段時間後重啟這個Observable

相關處理函式

處理錯誤相關的操作函式包括:

onErrorReturn

    public final Observable<T> onErrorReturn(Func1<java.lang.Throwable,? extends T> resumeFunction)

Instructs an Observable to emit an item (returned by a specified function) rather than invoking onError if it encounters an error.

一般出錯時,會呼叫onError,然後結束.使用onErrorReturn,onError不會呼叫,而是傳送onErrorReturn裡面提供的值,然後onCompleted會被呼叫. 注意,緊隨其後onCompleted會呼叫.

例子:

    Observable<String> observable = Observable.create(new OnSubscribe<String>(){
            @Override
            public void call(Subscriber<? super String> arg0) {
                arg0.onNext("a1");
                arg0.onNext("a2");
                arg0.onError(new Exception("testErrorReturn mock error"));
            }

        });

        observable.onErrorReturn(new Func1<Throwable, String>() {

            @Override
            public String call(Throwable arg0) {
                Utils.println("onErrorReturn call");
                return "aError";
            }
        })
        .subscribe(new Subscriber<String>() {

            @Override
            public void onCompleted() {
                Utils.println("onCompleted");
            }

            @Override
            public void onError(Throwable arg0) {
                Utils.println("onError");
            }

            @Override
            public void onNext(String arg0) {
                Utils.println("onResult:"+arg0);
            }
        });
輸出:
    onResult:a1
    onResult:a2
    onErrorReturn call
    onResult:aError
    onCompleted

onErrorResumeNext

宣告:

    public final Observable<T> onErrorResumeNext(final Observable<? extends T> resumeSequence) {
    public final Observable<T> onErrorResumeNext(final Func1<Throwable, ? extends Observable<? extends T>> resumeFunction);

如果原Observable發生錯誤時,不呼叫onError,而是使用一個新的Observable,呼叫它的call函式(其實就是訂閱它),裡面onNext的值回傳到subscriber,如果有調onCompleted,則subscriber會收到,如果沒有則不會收到. 即後續的行為由新的Observable決定了.

上面兩個函式的區別是第一個始終提供一個Observable,而第二個可以根據不同的Throwable提供不同的Observable.

例子:

        Observable<String> observable = Observable.create(new OnSubscribe<String>() {

            @Override
            public void call(Subscriber<? super String> arg0) {
                arg0.onNext("value1");
                arg0.onNext("value2");
                arg0.onNext("value3");
                arg0.onError(new Exception("mock testErrorResumeNext exception"));
                arg0.onNext("value4");
            }
        });
        Observable<String> resumeObservable = Observable.create(new OnSubscribe<String>() {

            @Override
            public void call(Subscriber<? super String> arg0) {
                arg0.onNext("valueMock1");
                arg0.onNext("valueMock2");
            }
        });

        observable.onErrorResumeNext(resumeObservable).subscribe(getSubscriber());
輸出:
    onResult:value1
    onResult:value2
    onResult:value3
    onResult:valueMock1
    onResult:valueMock2

如果resumeObservable呼叫onCompleted,則onCompleted會被呼叫.

onExceptionResumeNext

    public final Observable<T> onExceptionResumeNext(final Observable<? extends T> resumeSequence);

Instructs an Observable to pass control to another Observable rather than invoking Observer#onError if it encounters an Exception.

*** 和onErrorResumeNext類似,區別是onErrorResumeNext是針對onError的throwable,而onExceptionResumeNext僅僅是針對onError裡的型別是Exception. ***

retry

if a source Observable emits an error, resubscribe to it in the hopes that it will complete without error.

如果Observable.onError呼叫,即發射錯誤,會重新訂閱原來的Obserable,即重新觸發Observable,也就是從新調它的call函式.這種方式資料會重複.

  1. public final Observable<T> retry():
    無限重試,直到成功.
  2. public final Observable<T> retry(final long count):
    指定次數重試,超過指定次數還沒成功,則subscriber.onError會被呼叫.
  3. public final Observable<T> retry(Func2<Integer, Throwable, Boolean> predicate):
    傳入一個Fun2,裡面有兩個入參,一個表示目前引數的次數,另一個就是Observable.onError裡的型別,返回值true表示繼續重試,false表示不重試,Subscriber.onError會被呼叫.
    也就是說只要Observable.onError被呼叫後,會呼叫Func2去判斷是否要重試,Integer表示詢問重試的次數,從1開始.

retry(count)例子:

    Observable<String> observable = Observable.create(new OnSubscribe<String>() {

            @Override
            public void call(Subscriber<? super String> arg0) {
                arg0.onNext("value1");
                arg0.onNext("value2");
                arg0.onNext("value3");
                arg0.onError(new Exception("mock testRetryCount exception"));
                arg0.onNext("value4");
            }
        });

        observable.retry(1).subscribe(getSubscriber());
輸出:
    onResult:value1
    onResult:value2
    onResult:value3
    onResult:value1
    onResult:value2
    onResult:value3
    onError

從上面可以看出,重試了一次,後面不重試,Subscriber.onError被呼叫.另外由於重試,資料重複了.

retry(Func2)例子:

    Observable<String> observable = Observable.create(new OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> arg0) {
                arg0.onNext("value1");
                arg0.onNext("value2");
                arg0.onNext("value3");
                arg0.onError(new Exception("mock testRetryFunc2 exception"));
                arg0.onNext("value4");
            }
        });

        observable.retry(new Func2<Integer, Throwable,     Boolean>() {
            @Override
            public Boolean call(Integer arg0, Throwable arg1) {
                Utils.println("testRetryFunc2 func2::call time:"+arg0.intValue());
                return (arg0.intValue()>1)?false:true;
            }
        })
        .subscribe(getSubscriber());
輸出:
    onResult:value1
    onResult:value2
    onResult:value3
    testRetryFunc2 func2::call time:1
    onResult:value1
    onResult:value2
    onResult:value3
    testRetryFunc2 func2::call time:2
    onError

Integer從1開始,第一次重試,第二次返回false所以就不重試了,直接onError了.

retryWhen

    public final Observable<T> retryWhen(final Func1<? super Observable<? extends Throwable>, ? extends Observable<?>> notificationHandler);
    public final Observable<T> retryWhen(final Func1<? super Observable<? extends Throwable>, ? extends Observable<?>> notificationHandler, Scheduler scheduler);

if a source Observable emits an error, pass that error to another Observable to determine whether to resubscribe to the source

retryWhen的輸入引數是Func1,接受一個輸入Observable<Throwable>, 返回輸出引數Observable<?>。

返回的Observable<?>所要傳送的事件決定了重試是否會發生:

  • 如果傳送的是onCompleted或者onError事件,將不會觸發重訂閱。
  • 如果它傳送onNext事件,則觸發重訂閱(不管onNext實際上是什麼事件)。

這就是為什麼使用了萬用字元作為泛型型別:這僅僅是個通知(next, error或者completed),一個很重要的通知而已。

*** 可以理解為如果原Observable.onError發生, 如果Func1返回的Observable<?>的onNext被呼叫,則重新訂閱原來的Observable重試,否則不重試.***

輸入的Observable(即Func1裡Observable<?extends Throwable>)必須作為輸出Observable(即Func1的返回值)的源。我們必須對Observable<Throwable>做出反應,然後基於它傳送事件;不能只返回一個通用泛型流。

原Observable每次一呼叫onError(Throwable),Observable<Throwable>都會被作為輸入傳入方法中。換句話說就是,它的每一次呼叫我們都需要決定是否需要重訂閱。

下面的例子會重試:

source.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
              @Override public Observable<?> call(Observable<? extends Throwable> errors) {
                return errors.flatMap(new Func1<Throwable, Observable<?>>() {
                  @Override public Observable<?> call(Throwable error) {
                    return Observable.timer(5, TimeUnit.SECONDS);
                  }
                });
              }
            })

總結:

  1. onErrorReturn,吞掉錯誤,提供一個預設的返回值.
  2. onErrorResumeNext,吞掉錯誤,提供一個預設的Observable繼續傳送資料.
  3. onExceptionResumeNext,和onErrorResumeNext類似,區別是onErrorResumeNext是針對onError的throwable,而onExceptionResumeNext僅僅是針對onError裡的型別是Exception.
  4. retry,吞掉錯誤,按條件重新訂閱重試
  5. retryWhen,吞掉錯誤,由另外一個提供的Observable的行為決定是否重試,如果onNext被呼叫,則重新訂閱重試,onError或者onComplete被呼叫,則不重試.

RxJava特有的異常

  • CompositeException:
    表示發生了多個異常。你可以使用異常的 getExceptions() 方法獲取單獨的異常。

  • MissingBackpressureException:
    表示一個訂閱者或者操作符試圖對一個不支援反壓操作的Observable應用該操作。可以參考 [[Backpressure]] 查詢針對沒有實現反壓操作的Observable的解決辦法。

  • OnErrorFailedException:
    表示Observable嘗試呼叫觀察者的 onError() 方法,但是那個方法自己丟擲了異常。

  • OnErrorNotImplementedException:
    表示一個Observable嘗試呼叫它的觀察者的onError() 方法,但是那個方法不存在。有多種方法可以消除這個錯誤:可以調整Observable使它不會到達這個錯誤條件,也可以在觀察者中實現一個onError 處理器, 或者使用其它的操作符在錯誤到達之前攔截這個 onError 通知。

  • OnErrorThrowable:
    觀察者們可以用這種形式傳遞異常給它們的觀察者們的 onError() 方法。相比標準的Throwable,這種Throwable包含更多的資訊:錯誤本身和在錯誤發生時Observable的內部狀態。

...

...

Reference

  1. Error Handling Operators
  2. RxJava錯誤處理
  3. RxJava操作符(五)Error Handling
  4. RxJava 教程第三部分:馴服資料流之 高階錯誤處理

相關文章