Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit2 + RxJava error handling

I am using RxJava and Retrofit2 (with OkHttp as the HTTP client) to do networking and am trying to understand how different errors are handled by Retrofit2 and how they look from the RxJava side. The following code illustrates an RxJava Subscriber callback for a network call (made with Retrofit).

        Subscription subscription = observable
            .subscribeOn(mScheduler)
            .observeOn(mAndroidScheduler)
            .subscribe(new Subscriber<User>() {
                @Override
                public void onCompleted() {
                    Timber.d("onCompleted called");
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                }

                @Override
                public void onError(Throwable e) {
                    Timber.d("onError called");
                    Timber.d(e.toString());
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                }

                @Override
                public void onNext(User user) {
                    Timber.d("onNext called");
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                    mActivityView.launchMainActivity();
                }
            });

My question is, in what cases will onError() be called and once it's been called, how can I interrogate the Throwable to determine the cause?

From the Retrofit source it looks like the only Throwables that are possible to see are IOException and HttpException. Can anyone verify that that is true?

like image 856
neonDion Avatar asked Dec 19 '22 13:12

neonDion


1 Answers

Here's the basics: onError() will be called if:

  • the observable you're subscribing to throws an exception (e.g. you get an IOException while trying to read a file)
  • an exception is raised in your onNext() method.

If there's an exception in your onComplete(), RxJava will propagate an rx.exceptions.OnCompletedFailedException and if there's an exception in onError() - you'll get rx.exceptions.OnErrorFailedException.

That said, you can just probe the Throwable you receive in your onError() method for exceptions that you're expecting. For example you know that if your API call results in client error (4xx), Retrofit will wrap it into HttpException. If there's a timeout with the request you'll get a SocketTimeoutException. Here's a rough example:

@Override
public void onError(Throwable e) {
    Timber.d("onError called");
    Timber.d(e.toString());
    handleError(e);
}

private handleError(Throwable throwable) {
    if (throwable instanceof HttpException) {
        HttpException httpException = (HttpException)throwable;
        int statusCode = httpException.code();
        // handle different HTTP error codes here (4xx)
    } else if (throwable instanceof SocketTimeoutException) {
        // handle timeout from Retrofit
    } else if (throwable instanceof IOException) {
       // file was not found, do something
    } else {
       // generic error handling
       mRetainerView.clearUserObservable();
       mActivityView.hideProgressBar();
       mActivityView.enableUi();
}
like image 67
Vesko Avatar answered Dec 27 '22 13:12

Vesko