A very convenient and flexible way to implement centralized logging is just to have a handler that is reused in the places where the general exception (error) handling is needed.
Basically, it will be a class that implements the Consumer<Throwable> interface. This way, it can be plugged in anywhere the RxJava is consuming that interface. This includes methods such as .doOnError() or the .subscribe() block.
Let's take a look at how it can be implemented:
public class ErrorHandler implements Consumer<Throwable> {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e("APP", "Error on " + Thread.currentThread().getName() +
":", throwable);
}
}
Since it is supposed to be used as a global handler of errors, it makes sense to make this class a singleton. To do that, add the following lines:
private static final ErrorHandler INSTANCE = new ErrorHandler();
public static ErrorHandler get() {
return INSTANCE;
}
private ErrorHandler() {
}
Now the class can be used in Observable flows. Consider the following example:
Observable.<String>error(new Error("Crash!"))
.doOnError(ErrorHandler.get())
.subscribe(item -> {
log("subscribe", item);
}, ErrorHandler.get());
The beauty of this approach is that there can be multiple handlers like that. A developer can have something like WarnOnlyHandler that can be used to show only warnings instead of full exceptions or a handler that logs errors to some remote service only for specific parts of the application.
However, the bad thing is that we must always keep passing the ErrorHandler.get() call, and that can start to become a bit annoying later on.