Rx Chain Retrier

Oleh Haidaienko
ProAndroidDev
Published in
4 min readOct 29, 2018

--

Very often you need to retry network request, for example, when a user does not have a connection to the Internet and he requests some data. It’s a good practice to show some UI element and explain to the user what happened and give a chance to retry failed request. Implementing retry logic can be a bit painful, especially when you have a lot of ViewModel classes. Of course, you can define some retry logic in each ViewModel, but it’s inconvenient because you can easily make mistake somewhere.

Is there a way to handle this case in one place?

Fortunately, RxJava2 and Retrofit2 can help you with this.

On Stackoverflow there are a few solutions:

  • Create custom CallAdapterFactory(click here for details)
  • Repeat the chain using PublishSubject (click here for details)

In first solution RxJava1 is used so it’s obsolete now and also it just retries chain a few times but not when some event received. The second solution good but you need to add retryWhen() operator to each chain.
So I have merged these two solutions into one.

Implementation

Let’s create a simple project. On the main screen put two tabs. On each of this tab display text which will show how many items loaded from API. If some error occurred we’ll show snackbar with Try again action.

Example the app

Define base classes such as BaseActivity, BaseFragment, BaseViewModel these classes needed for implementing retry logic in one place and avoid code duplication. Create two fragments and extend from BaseFragment. Each fragment that placed in a particular tab has own ViewModel and respectively making a request to API. I have created these fragments in order to show that if an error occurs each request will be retried.
Then create factory RxRetryCallAdapterFactory which extends CallAdapter.Factory. After this create instanse of RxJava2CallAdapterFactory. We need this instance for getting access to RxJava2CallAdapter as we don’t want to duplicate code which already exists in the Retrofit library. Also, let’s create a static method which will return an instance of our factory. Code sample of this factory below:

Next, create RxRetryCallAdapter which implements interface CallAdapter and we have to pass an instance of CallAdapter into the constructor. In fact, it will be an instance of RxJava2CallAdapter which returned by the original factory.

Next few things are very important as they transform adapted value and responsible for retrying the chain. Let’s define the goal of each point:

  • retryWhen operator used for implementing retry funtionality
  • doOnError() operator which handling error, used for sending broadcast which will be handled by BaseActivity and show snackbar to the user
  • PublishSubject used as event trigger which resubscribes the chain
  • observeOn(Schedulers.io()) operator which need to be applied to PublishSubject(if you don’t add this you will get NetworkOnMainThreadExceptionas chain resubscribed on the main thread)
  • transform PublishSubject to Flowable and set backpressure to BackpressureStrategy.LATEST as we need only last error

Note: For providing PublishSubject I created simple singleton class which provides all singleton dependencies in the project. In the real project you will probably use a dependency injection framework, like Dagger2

When the user clicks on Try again button we call onNext(Unit) of PublishSubject that we provided. After this, reactive chain will be resubscribed.

Testing

Turn off internet connection and run the application. Number of loaded items equals to zero on each tab and snackbar with error message displayed. Turn on internet connection and click on Try again button of snackbar. After a few seconds, number of loaded items changed on every tab.

Conclusion

There are a few ways to retry rx chain and you decide what to choose. But I hope that this article helps you to retry your chains in a more reactive way, what eventually will save a little bit of your time.
Happy coding!
If someone needs source code you can check it here.
Thanks for reading! If you liked this article press 👏 I would like to hear from you how you handle case described in this article so please, suggest other ways or improvements in comments. See ya!

--

--