RxJava操作符(06-錯誤處理)

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

目錄:

文章目錄

1. Catch

  Catch操作符能夠攔截原始Observable的onError通知,不讓Observable因爲產生錯誤而終止。相當於java中try/catch操作,不能因爲拋異常而導致程序崩潰。 retry操作符默認在trampoline調度器上執行。

    這裏寫圖片描述

RxJava將Catch實現爲三個不同的操作符:

  • onErrorReturn:onErrorReturn方法返回一個原有Observable行爲的新Observable鏡像,後者會忽略前者的onError調用,不會將錯誤傳遞給觀察者,作爲替代,它會發發射一個特殊的項並調用觀察者的onCompleted方法。

    • Javadoc: onErrorReturn(Func1)

    這裏寫圖片描述

  • onErrorResumeNext:讓Observable在遇到錯誤時開始發射第二個Observable的數據序列。 onErrorResumeNext方法返回一個原有Observable行爲的新Observable鏡像 ,後者會忽略前者的onError調用,不會將錯誤傳遞給觀察者,作爲替代,它會開始發射鏡像Observable的數據。

    • Javadoc: onErrorResumeNext(Func1)
    • Javadoc: onErrorResumeNext(Observable)

    這裏寫圖片描述

  • onExceptionResumeNext: 讓Observable在遇到錯誤時繼續發射後面的數據項。 和onErrorResumeNext類似,onExceptionResumeNext方法返回一個鏡像原有Observable行爲的新Observable,也使用一個備用的Observable,不同的是,如果onError收到的Throwable不是一個Exception,它會將錯誤傳遞給觀察者的onError方法,不會使用備用的Observable。

    • Javadoc: onExceptionResumeNext(Observable)

    這裏寫圖片描述

示例代碼:
  注意:在測試onExceptionResumeNext 的時候,不妨試試onError中發射Throwable的情況,這種情況會將onError通知發送給訂閱者,並停止。

/*
 * ①.onErrorReturn:
 * 返回一個原有Observable行爲的新Observable鏡像,
 * 後者會忽略前者的onError調用,不會將錯誤傳遞給觀察者,
 * 作爲替代,它會發發射一個特殊的項並調用觀察者的onCompleted方法
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0;i < 10; i++){
            if(i>3){
                //會忽略onError調用,不會將錯誤傳遞給觀察者
                subscriber.onError(new Throwable("i太大了"));
            }
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
}).onErrorReturn(new Func1<Throwable, Integer>() {
    //作爲替代,它會發發射一個特殊的項並調用觀察者的onCompleted方法。
    @Override
    public Integer call(Throwable throwable) {
        return 10;
    }
}).subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "①onErrorReturn(Func1)->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e(TAG, "①onErrorReturn(Func1)->onError:"+e.getMessage());
    }
    @Override
    public void onNext(Integer integer) {
        Log.v(TAG, "①onErrorReturn(Func1)->onNext:"+integer);
    }
});

/*
 * ②.onErrorResumeNext(Observable):
 * 當原Observable發射onError消息時,會忽略onError消息,不會傳遞給觀察者;
 * 然後它會開始另一個備用的Observable,繼續發射數據
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0;i < 10; i++){
            if(i>3){
                //會忽略onError調用,不會將錯誤傳遞給觀察者
                subscriber.onError(new Throwable("i太大了"));
            }
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
}).onErrorResumeNext(Observable.create(new Observable.OnSubscribe<Integer>() {

    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 10;i < 13; i++){
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
})).subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "②onErrorResumeNext(Observable)->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e(TAG, "②onErrorResumeNext(Observable)->onError:"+e.getMessage());
    }
    @Override
    public void onNext(Integer integer) {
        Log.v(TAG, "②onErrorResumeNext(Observable)->onNext:"+integer);
    }
});

/*
 * ③.onErrorResumeNext(Func1):
 * 和onErrorResumeNext(Observable)相似,但他能截取到原Observable的onError消息
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0;i < 10; i++){
            if(i>3){
                //會忽略onError調用,不會將錯誤傳遞給觀察者
                subscriber.onError(new Throwable("i太大了"));
            }
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
}).onErrorResumeNext(new Func1<Throwable, Observable<? extends Integer>>() {
    @Override
    public Observable<? extends Integer> call(Throwable throwable) {
        //throwable就是原Observable發射的onError消息中的Throwable對象
        Log.e(TAG, "③onErrorResumeNext(Func1)->throwable:"+throwable.getMessage());
        //如果原Observable發射了onError消息,將會開啓下面的Observable
        return Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                for(int i = 100;i < 103; i++){
                    subscriber.onNext(i);
                }
                subscriber.onCompleted();
            }
        });
    }
}).subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "③onErrorResumeNext(Func1)->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e(TAG, "③onErrorResumeNext(Func1)->onError:"+e.getMessage());
    }
    @Override
    public void onNext(Integer integer) {
        Log.v(TAG, "onErrorResumeNext(Func1)->onNext:"+integer);
    }
});

/*
 * ④.onExceptionResumeNext:
 *    和onErrorResumeNext類似,可以說是onErrorResumeNext的特例,
 *    區別是如果onError收到的Throwable不是一個Exception,它會將錯誤傳遞給觀察者的onError方法,不會使用備用的Observable。
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0;i < 10; i++){
            if(i>3){
                //如果不是Exception,錯誤會傳遞給觀察者,不會開啓備用Observable
                //subscriber.onError(new Throwable("i太大了"));
                //如果Exception,不會將錯誤傳遞給觀察者,並會開啓備用Observable
                subscriber.onError(new Exception("i太大了哦哦哦"));
            }
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
}).onExceptionResumeNext(Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 10;i < 13; i++){
            subscriber.onNext(i);
        }
        subscriber.onCompleted();
    }
})).subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "④onExceptionResumeNext(Observable)->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e(TAG, "④onExceptionResumeNext(Observable)->onError:"+e.getClass().getSimpleName()+":"+e.getMessage());
    }
    @Override
    public void onNext(Integer integer) {
        Log.v(TAG, "④onExceptionResumeNext(Observable)->onNext:"+integer);
    }
});

輸出:

①onErrorReturn(Func1)->onNext:0
①onErrorReturn(Func1)->onNext:1
①onErrorReturn(Func1)->onNext:2
①onErrorReturn(Func1)->onNext:3
①onErrorReturn(Func1)->onNext:10
①onErrorReturn(Func1)->onCompleted

②onErrorResumeNext(Observable)->onNext:0
②onErrorResumeNext(Observable)->onNext:1
②onErrorResumeNext(Observable)->onNext:2
②onErrorResumeNext(Observable)->onNext:3
②onErrorResumeNext(Observable)->onNext:10
②onErrorResumeNext(Observable)->onNext:11
②onErrorResumeNext(Observable)->onNext:12
②onErrorResumeNext(Observable)->onCompleted

③onErrorResumeNext(Func1)->onNext:0
③onErrorResumeNext(Func1)->onNext:1
③onErrorResumeNext(Func1)->onNext:2
③onErrorResumeNext(Func1)->onNext:3
③onErrorResumeNext(Func1)->throwable:i太大了
③onErrorResumeNext(Func1)->onNext:100
③onErrorResumeNext(Func1)->onNext:101
③onErrorResumeNext(Func1)->onNext:102
③onErrorResumeNext(Func1)->onCompleted

④onExceptionResumeNext(Observable)->onNext:0
④onExceptionResumeNext(Observable)->onNext:1
④onExceptionResumeNext(Observable)->onNext:2
④onExceptionResumeNext(Observable)->onNext:3
④onExceptionResumeNext(Observable)->onNext:10
④onExceptionResumeNext(Observable)->onNext:11
④onExceptionResumeNext(Observable)->onNext:12
④onExceptionResumeNext(Observable)->onCompleted

2. Retry

  顧名思義,retry的意思就是試着重來,當原始Observable發射onError通知時,retry操作符不會讓onError通知傳遞給觀察者,它會重新訂閱這個Observable一次或者多次(意味着重新從頭髮射數據),所以可能造成數據項重複發送的情況。
  如果重新訂閱了指定的次數還是發射了onError通知,將不再嘗試重新訂閱,它會把最新的一個onError通知傳遞給觀察者。

    這裏寫圖片描述

RxJava中將Retry操作符的實現爲retry和retryWhen兩種:

  • retry:
    • Javadoc: retry():無論收到多少次onError通知,都會繼續訂閱並重發原始Observable,直到onCompleted。

    • Javadoc: retry(long):接受count參數的retry會最多重新訂閱count次,如果次數超過了就不會嘗試再次訂閱,它會把最新的一個onError通知傳遞給他的觀察者。

    • Javadoc: retry(Func2): 這個版本的retry接受一個謂詞函數作爲參數,這個函數的兩個參數是:重試次數和導致發射onError通知的Throwable。這個函數返回一個布爾值,如果返回true,retry應該再次訂閱和鏡像原始的Observable,如果返回false,retry會將最新的一個onError通知傳遞給它的觀察者。

示例代碼:

/**
 * ①. retry()
 *     無限次嘗試重新訂閱
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0; i<3; i++){
            if(i==1){
                Log.v(TAG, "①retry()->onError");
                subscriber.onError(new RuntimeException("always fails"));
            }else{
                subscriber.onNext(i);
            }
        }
    }
}).retry()    //無限次嘗試重新訂閱
.subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "①retry()->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "①retry()->onError"+e.getMessage());
    }
    @Override
    public void onNext(Integer i) {
        Log.v(TAG, "①retry()->onNext"+i);
    }
});

/**
 * ②. retry(count)
 *     最多2次嘗試重新訂閱
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0; i<3; i++){
            if(i==1){
                Log.v(TAG, "②retry(count)->onError");
                subscriber.onError(new RuntimeException("always fails"));
            }else{
                subscriber.onNext(i);
            }
        }
    }
}).retry(2)    //最多嘗試2次重新訂閱
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.v(TAG, "②retry(count)->onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.v(TAG, "②retry(count)->onError"+e.getMessage());
            }
            @Override
            public void onNext(Integer i) {
                Log.v(TAG, "②retry(count)->onNext"+i);
            }
        });

/**
 * ③. retry(Func2)
 */
Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        for(int i = 0; i<3; i++){
            if(i==1){
                Log.v(TAG, "③retry(Func2)->onError");
                subscriber.onError(new RuntimeException("always fails"));
            }else{
                subscriber.onNext(i);
            }
        }
    }
}).retry(new Func2<Integer, Throwable, Boolean>() {
    @Override
    public Boolean call(Integer integer, Throwable throwable) {
        Log.v(TAG, "③發生錯誤了:"+throwable.getMessage()+",第"+integer+"次重新訂閱");
        if(integer>2){
            return false;//不再重新訂閱
        }
        //此處也可以通過判斷throwable來控制不同的錯誤不同處理
        return true;
    }
}).subscribe(new Subscriber<Integer>() {
    @Override
    public void onCompleted() {
        Log.v(TAG, "③retry(Func2)->onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.v(TAG, "③retry(Func2)->onError"+e.getMessage());
    }
    @Override
    public void onNext(Integer i) {
        Log.v(TAG, "③retry(Func2)->onNext"+i);
    }
});

輸出:

①retry()->onNext0
①retry()->onError
①retry()->onNext0
①retry()->onError
…無限次

②retry(count)->onNext0
②retry(count)->onError
②retry(count)->onNext0
②retry(count)->onError
②retry(count)->onNext0
②retry(count)->onError
②retry(count)->onErroralways fails

③retry(Func2)->onNext0
③retry(Func2)->onError
③發生錯誤了:always fails,第1次重新訂閱
③retry(Func2)->onNext0
③retry(Func2)->onError
③發生錯誤了:always fails,第2次重新訂閱
③retry(Func2)->onNext0
③retry(Func2)->onError
③發生錯誤了:always fails,第3次重新訂閱
③retry(Func2)->onErroralways fails

  • retryWhen:
      retryWhen和retry類似,區別是,retryWhen將onError中的Throwable傳遞給一個函數,這個函數產生另一個Observable,retryWhen觀察它的結果再決定是不是要重新訂閱原始的Observable。如果這個Observable發射了一項數據,它就重新訂閱,如果這個Observable發射的是onError通知,它就將這個通知傳遞給觀察者然後終止。

示例代碼:

Observable.create((Subscriber<? super String> s) -> {
    System.out.println("subscribing");
    s.onError(new RuntimeException("always fails"));
}).retryWhen(attempts -> {
    return attempts.zipWith(Observable.range(1, 3), (n, i) -> i).flatMap(i -> {
        System.out.println("delay retry by " + i + " second(s)");
        return Observable.timer(i, TimeUnit.SECONDS);
    });
}).toBlocking().forEach(System.out::println);

輸出:

subscribing
delay retry by 1 second(s)
subscribing
delay retry by 2 second(s)
subscribing
delay retry by 3 second(s)
subscribing

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

#源碼下載:

https://github.com/openXu/RxJavaTest

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