I do not aim to explain various operators available in Rx. The aim is to explain the fundas so that, you can confidently tackle any given situation.

Agenda

When I started with RxJava, I aimed to get fluent in it. I wanted to reach a level where I could use as many operators as fluently as I can. With time that desire diminished when I saw the number of operators in the Rx documentation. I knew one thing, that the approach I took was wrong. I have to get the basics right and I could use the operators anytime just by looking at the documentation. For me, initially while working with Rx, error handling was calling onError() on emitters while creating the observables and overriding onError(Throwable throwable) while observing it. But that is not enough.

In this post, I am just going to talk about Rx error handling, and how to use it efficiently. We will start with basics and then talk about real-world cases. For demonstration purposes, we are going to play around with an Observable<Employee>. It is going to emit employees one by one. This is going to be a long post so please be ready.

// Do not look at code, it just emits employees with random data
public List<Employee> getEmployees() {
List<Employee> result = new ArrayList<>();
ThreadUtil.threadInfo();
for(int i=0 ; i<100 ; i++) {
Employee e = new Employee();
e.ID = i + ((i*7)%3)*67;
e.name = "Employee "+i;
e.salary = Integer.valueOf(e.name + e.ID) + (100- Integer.valueOf(e.name + e.ID)%100);
result.add(e);
}
return result;
}

To understand error handling in RxJava we must know how the error flows through the lifecycle of the subscription.

Understanding the direction of error flow in Rx

Whenever onError() is called for your observer, it means the subscription will be disposed of before you call next onNext() call. If you call onNext() on your emitter after that by any chance, it will not be delivered to your onNext() or onError(). OnError() is meant for handling errors that happen during the life span of the subscription. It will never get fired before the subscription happens and after the subscription has ended.

Use emitter.onError() only for cases when you want the subscription to end. The chain is disposed of before the Rx calls onError(). If you dare to call emitter.onNext() after a call to the emitter.onError(), Rx will raise UnDeliverableException(We will see where it goes in a while)” A short snippet from Rx source code.

Let’s see some bad code.

You will never throw an exception like this in real life but this is just for mimicking a runtime exception. In real life, for some value of an employee, our disk writes or DB calls might fail. We see there are 2 ways in which we are throwing an error and both of them are going to produce different results. When we do throw new RuntimeException(“Bad Employee: “+ employee.ID), the method ends there and Rx routes it to onError() and it prints “Caught!” and everything ends there. Here we are not able to call onNext() after the exception is thrown but in the second case, we are calling onNext() even after calling onError(), the method does not finish. So, as we discussed, Rx raises a UndeliverableException for all remaining onError emissions and it is not passed to onError(). It leads to an app crash!

So how to prevent it? The idea is to guard the code properly with isDisposed() before calling onNext()/onError()/onComplete()

Now, what if, you internally use try-catch to handle the runtime exceptions? In that case, Rx will not know what went wrong and it will continue delivering the values to the observers like the code below.

This will never flag a problem. But we shouldn’t be catching a runtime exception as it should be fixed most of the time.

Below is an illustration of how error flows in the system.

Error flow in RxJava

When does RxJavaPlugin’s error handler shine?

So, now that we know how to handle errors in the span of subscription. Now we will see, what to do if errors do not trigger the onError() callback as the subscription has either ended or not started.

We take the previous buggy example in Snippet B, way 1, where we are calling onNext() after calling onError(). It will raise UndeliverableExceptions.

This is where RxJavaErrorHandler comes into the picture.

RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Utils.log("Received in error handler");
// What caused this? To find out we can log this on crash reporting tools
    }
});

Once you install the error handler, it will catch all errors after your subscription is disposed of and it will catch errors before the observable is subscribed(Errors before observer’s onSubscribe() is called ).

This is a snippet from StackOverflow as an example for fromCallable

Single.fromCallable(() -> someIoOperation()).
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(value -> updateUi(value), error -> handleError(error));
While using Observable.fromCallable, unlike the above examples we cannot check whether the subscription is disposed or not. So, if at all fromCallable ends up emitting after the subscription has ended. The app will crash. To handle those kinds of cases, RxJavaPlugins.errorHandler can prove to be a good candidate. If we do not do it, it will make our apps crash!
If we have a default error handler installed in Rx plugins, we do not even have to keep our onError() overrides in our observables and we won’t get onErrorNotImplementedException.
It is always a good idea to have an error Handler installed to catch any unknown cases and log them with crash reporting tools so that we can understand what caused them.

Reporting Errors and logging them is not something we would like to do in all real-life use cases. We expect our software to have a fallback mechanism if some errors are encountered.

Understanding some fallback mechanisms in RxJava

onErrorReturnItem(): Suppose you have a mobile app where you need to show a grid of products that need to be displayed to the user, something like a catalog. You make web calls(returning List<Bitmap>)to fetch the list of product icons and the web call somehow fails due to some reason. It would be nice if you show some placeholder icons on the screen and still let the caller code be agnostic about the failure. We can do this by providing fallback data, Rx will return that fallback data instead of calling onError(). In the above case what if, I want to get fallback employee data in case of error. This can be done using onErrorReturnItem. This will return List<Bitmap> but will have only one item inside ie. the place holder.

onExceptionResumeNext(): Imagine a scenario where we have to download a list of N images. We successfully download ’n’ images but n/w error happens in between. We might want to show the cached data to the user for the time being instead of showing nothing or error. By using this operator when an exception happens we can switch to another observable instead of routing it to onError. In the upcoming example, we are pulling employee data but exception occurs, onExeceptionResumeNext lets us create another list of fallback observable instead of notifying onError().

doOnError(): This is used as a side effect operator. It is just like a hook, it gets executed with the throwable and the chain continues. This is not a replacement for onError(). This should be only used for code which is not a part of the main execution chain. We can use this for handling logging, progress bars, etc. Not giving any example for this.

There are many more operators which you can explore yourself.

Thanks.