Effective Networking On Android using Retrofit, Rx and Architecture Components

karntrehan
MindOrks
Published in
3 min readFeb 10, 2018

For many, like me, Retrofit is the go-to library on Android to talk to their REST APIs. Retrofit also supports adapters to convert your API responses into Reactive Streams. Reactive streams, among other things, help you handle threading effectively. This makes your Android application robust, stable and development faster.

For simpler use cases, the integration of Retrofit + Rx can be read about here and here. This advanced post tries to go to the next level and allow you to do the following:

  • Integrate Rx + Retrofit + Android Architecture Components (AAC)
  • Use a multimodule project with MVVM architecture
  • Use Kotlin and its sealed classes to maintain state
  • Handle errors effectively
  • Respect the lifecycle of Android components.

You can find a sample app supporting this architecture here:

Implementation

Architecture

We follow an MVVM architecture with the AAC’s ViewModel helping our views to communicate with repositories. All of these are glued together using Dagger 2. Our single source of truth is the local database on which we use AAC’s Room ORM

At the core of the architecture is the Outcome.kt sealed class

Outcome.kt

The outcome holds the state of the screen. It can be

  • loading(isLoading) — where isLoading represents data lookup & can be used to show or hide a progress bar.
  • success(data) — where data is the data you would want to show on the UI
  • failure(exception) — where exception represents any error that could have failed the data lookup.

Flow

The outcome object is observed at different layers in the following way:

Flow of Outcome through the layers
  1. Events from your activity are passed onto the viewmodel

2. The viewmodel relays the events to the repository

3. The repository create a PublishSubject for the Outcome class

4. The repository starts observing the contents of the local database, pushes it to the publishSubject.success(data) and pings the server the first time to fetch remote update.

5. The remote sync on success, saves to the internal db. This triggers the publishSubject.success(data). On error, the error from the server is converted to an exception and pushed to the publishSubject.Error(exception)

6. The viewmodel has a LiveData object observing the publishSubject of the repository

7. The activity is observing the viewmodel’s LiveData object and updates the screen contents accordingly

Conclusion

  • Loading / Data / Error, all states are reacted to by the activity
  • Exceptions from network sync can also be pushed as non-fatals to Crashlytics to debug later.
  • Due to the ViewModel and Dagger Scopes, the lifecycles of the Android components are respected and there are no leaks of context as well as data.
  • The ViewModel and Repository can be tested in isolation.
  • Room can be replaced with ObjectBox.

Please feel free to play around with the sample app. Pull requests and issues are very much welcomed. Thank you!

--

--