Search code examples
javaandroidrx-javareactive-programmingrx-android

Use Fallback Observable x number of times


I have an Observable which implements Error handling in the onErrorResumeNext method.

getMyObservable(params)
                .take(1)
                .doOnError(e -> {
                })
                .onErrorResumeNext(throwable -> {
                    if (throwable.getMessage().contains("401")) {
                        return getMyObservable(params);
                    } else {
                        sendServerCommunicationError();
                        return Observable.error(throwable);
                    }
                })
                .subscribe(result -> {
                             ...                                }
                });

GetMyObservable() returns a web service request from a generated client. The Use Case is: If we receive 401 we may need to refresh the client with a new UserToken. That is why we use the Fallback Observable in onErrorResumeNext() and cannot just use retry.

I have some questions:

  1. Why do I need to implement doOnError? If I don´t implement it, I sometimes get an "onError not implemented" Exception. I thought when I use onErrorResumeNext, this method is automatically used in case of an Error.
  2. How can I achieve that on specific Errors (like 401) I use a fallback Observable with some backoff time and after 5 Times I produce an Error. So can I combine retryWhen and onErrorResumeNext somehow or is it done differently?

Solution

  • Why do I need to implement doOnError?

    You don't and doOnError is not an error handler but a peek into the error channel. You have to implement an error handler in subscribe:

    .subscribe(result -> {
        // ...
    },
    error -> {
        // ...
    });
    

    How can I achieve that on specific Errors (like 401) I use a fallback Observable with some backoff time and after 5 Times

    Use retryWhen:

    Observable.defer(() -> getMyObservable(params))
    .retryWhen(errors -> {
        AtomicInteger count = new AtomicInteger();
        return errors.flatMap(error -> {
           if (error.toString().contains("401")) {
               int c = count.incrementAndGet();
               if (c <= 5) {
                   return Observable.timer(c, TimeUnit.SECONDS);
               }
               return Observable.error(new Exception("Failed after 5 retries"));
           }
           return Observable.error(error);
        })
    })