Reactive Views: retrying errors

Alberto Ballano
New Work Development
3 min readNov 9, 2016

--

This post was featured in Android Weekly’s #231 issue.

After having a good adoption of RxJava and clean architecture in our XING Android app codebase we’ve been lately considering about iterating more over our already implemented passive view concept in MVP, as a result we found couple of interesting articles about Reactive Views, specially this one from Artem Zinnatullin, which illuminated our way to go for following improvements to the pattern in our app.

As Artem mentions in his article, RxBinding works really well with this Reactive Views approach, even though some UI components don’t have their binding in the library, implementing them manually by just looking at the source code of others is pretty straightforward.

The feature

We had to implement a simple feature in our Messenger app: when the user long clicks on a chat we have to show a dialog to confirm its deletion.

View Binding

So, since our view is currently almost 100% passive our initial approach was to expose an Observable bound to the RecyclerView’s item long click and get it from the presenter, but unfortunately RxBinding doesn’t (and won’t) contain any binds for this approach, so we decided to write our own.

The usage is pretty simple by using the same syntax as RxBinding:

Ok so now that we can easily forward each of our RecyclerView’s item long clicks to an Observable, let’s see the implementation in the View:

Presenter action

The presenter will then be bound to this observable in it’s initialization. Any long press will cause the chain to trigger making the Presenter aware of the event so it tells the View to show the dialog.

If the user confirms the deletion the View will then inform* the presenter by calling onDeleteChat and this one will make the network request:

*Note that here we are breaking our Rx chain since the Dialog we’re using in our app doesn’t allow, for now, to be bound with Observables, but for normal cases that shouldn’t be a problem.

The error case

But what happens if this request fails? We need to let the user know about this issue and even let him retry the operation, so what we wanted to do is to show a Snackbar with a “retry” action on it as shown in the Material Design specification.

Since we’re working with Observables, would be really nice to use the retryWhen operator so we don’t have to worry about manually retrying anymore.

View binding

But, in order to achieve this, we first need to “Rxify ” our Snackbar as we did with the RecyclerView’s item long click, and since, again, RxBindings doesn’t have (yet) a binding for it, we need to create one ourselves, so that we did.

Again, nothing really complicated, right? So now we again exposed a method in the view for this like the following:

Presenter action

So now we temporarily implemented the retryWhen incorrectly in our presenter and thus the code should be modified to look this way:

But as I said, this is wrong! Why? Because that’s not how retryWhen works!

The problem is that we were using a Completable since our API policy in this case is to make the request and either succeed or fail, we don’t expect response, and, in my opinion, the javadoc is not clear enough (but is fixed in RxJava 2) about what you have to do with the given Observable:

Returns a Completable which given a Publisher and when this Completable emits an error, delivers that error through an Observable and the Publisher should return a value indicating a retry in response or a terminal event indicating a termination.

After struggling with our tests not passing, we found this great post by Dan Lew with some nice clarifications plus a bonus point on the exact same problem:

The output Observable has to use the input Observable as its source. You must react to the Observable<Throwable> and emit based on it; you can't just return a generic stream.

So, here’s the fixed code:

Summary

That’s it! We made our view totally passive by just following the “orders” of the Presenter and by exposing observables from the user input, that way we make a full reactive chain which is really easy to test with the minimum effort, apart from creating our own Rx bindings :P which shouldn’t be the normal case anyway.

--

--