RxJava: Android MVVM App structure with Retrofit

Manuel Vivo
14 min readAug 28, 2015

Introduction

Creating an App structure for Android which is easy to maintain and debug is not always easy. The more Network communications and interaction between Views the app contains, the more difficult it will be.

One of the things I really appreciate about a good structure is when you have a defect in your app and you know exactly where to go to fix it.

In this article we’ll learn how to create a structure which uses both RxJava and Retrofit. We’ll focus on RxJava, probably you’ve heard a lot about this but when you try to get your head around it, is a bit of a nightmare.

Hands On

Before starting, it would be worth to mention that I created a repository with an example quite similar to the one explained below. It’s always good to have a full example where you can see everything related.

This article doesn’t explain anything about Unit Testing, however, in that repository you have some examples which might be useful for you.

https://github.com/manuelvicnt/RxJava-android-structure

Structure

Model View ViewModel (MVVM) is the architectural pattern we should use in Android. The Views will only show information, they won’t do any logic at all because for that, we have ViewModels. I’ll assume you know how this pattern works, if not, you can read more about it here.

At least, we should have one ViewModel per Fragment (view).

Networking

The networking part can be the most difficult one depending on different factors such as: how often, from how many places you call them, if you have to concatenate or combine different requests, etc.

I like to give each class its purpose. We know about the View and the ViewModel purposes: show information, handle the information the view has to show. For Networking… what would we need? First of all, if we use Retrofit, we’ll have to create the Interface for different endpoints and a class to fire its requests. Let’s call this kind of class APIService. For example, for the registration process we will have the RegistrationAPIService, for login: LoginAPIService, etc. This class can also handle the different errors, the logic to apply when it succeeds, etc.

We will also need a class in charge of preparing the data for the request. This class can be the ViewModel, but… What about if we call the same request from different ViewModels? We’ll have to repeat the same code and change the same things if something’s wrong. What about if we have to combine network requests? We’ll have to put the same logic again in different ViewModels… It seems like we can create another class whose purpose is preparing the data and linking different requests. Let’s call this kind of class RequestManager. As before, we can have something like: UserAuthenticationRequestManager (in charge of login and registration), UserDataRequestManager (for getting the user’s data), etc.

Summing up: Views show information. ViewModels handle the information its View has to show. RequestManagers prepare networking data and link different requests. APIServices make the request, handle the response and the errors.

Interactions

Probably, we can see the structure better with an example:

  1. The user taps a button because he wants to register.
  2. The Fragment tells the ViewModel (VM) that the button has been tapped (and probably, it shows a loading dialog animation saying we’re processing the request).
  3. The VM handles what it has to be done. In this case, because the user wants to register into the app, it tells the UserAuthenticationRequestManager (RM) to register.
  4. The RM prepares the data (which is passed from the VM or it gets it from a RegistrationModel, for example) and talks with the RegistrationAPIService to register the user with that data.
  5. The RegistrationAPIService makes the request (also handles the error just in case something went wrong) and when it receives the response, it processes the information (for example, storing it somewhere). After that, it communicates to the RM that everything was OK and the user is registered.
  6. Then, the RM gets the confirmation that registration was successful. Oh wait, but we also have to log the user in (because of our requirements)! Then, the RM prepares the Login data to make the request. When it’s prepared, it communicates with the LoginAPIService.
  7. The LoginAPIService makes the request and does everything the RegistrationAPIService did before (handling errors, applying the logic, parsing the data, etc). Again it tells the RM that the request was successful.
  8. The RM has nothing else to do, so it can tell the ViewModel and the ViewModel to the View that the user is registered and logged in.
  9. Now, the Fragment reacts according the response it got.
App structure with Networking

Tips for RxJava

I assume you already know few things about RxJava. I learnt from different sources of information such as: RxJava documentation, @Dan Lew Codes, @Timo Tuominen and other tutorials.

For this article, I used ‘me.tatarka:gradle-retrolambda:3.2.2’ and ‘io.reactivex:rxandroid:1.0.0’ as the libraries for RxJava.

RxJava Tips

When working with RxJava, not everything works as expected or as you imagined (harsh reality). This is because in your mind, it should work but probably you missed something while reading about it, or how you implemented it completely differs from how it should be. Here, there are few tips I learnt:

  • Don’t subscribe to another Observable inside Actions (it’s not going to work).
  • When an object Subscriber subscribes to an Observable, it will only call its methods once. I guess this is because when the subscriber is unsubscribed from an Observable, it cannot subscribe again. So, when you subscribe to an Observable, you always have to create a new instance! If you don’t like creating anonymous classes (as the parameter for subscribe), you can create a class which extends from Subscriber and create a new instance of that class when subscribe.
  • This may seem stupid but remember: if onError is executed on a Subscriber, onComplete won’t be called.
  • CompositeSubscriptions make things more difficult. It’s easier subscribe and unsubscribe manually from your Observables.
  • If only one Subscriber listens for an Observable, once this unsubscribes, the Observable will stop. For Retrofit, that means that if your View subscribes to the Retrofit call directly, if you call unsubscribe in onPause, it will “cancel” the network request; so you will never receive the response in the View (you won’t know if it succeeded or not).
  • Not sure why, but Subjects never execute its onSubscribe, onError, onNext, etc, methods.
  • If you want to throw an exception from a FuncX function, you can always use return Observable.error(yourException). If you want to throw an exception from a ActionX function, then you’ll have to catch the different exceptions the method contains and throw them manually.

When you subscribe to an Observable, always create a new instance

Retrofit Specific Tips

  • If you want to get the status code of your Retrofit response, You will have to parse the body manually since you’ll need to get the ‘retrofit.client.Response’ object as the response.
  • If you want to get the error status code of your Retrofit response, onError method, cast the Throwable object you get from the parameter to an RetrofitError and do it as you usually do without RxJava.

Implementation with RxJava

Let’s code something now. We’ll implement the different parts we talked about before, the implementation is highly tight to the tips from the previous section. It’s possible that with new versions of the libraries things can change a little bit, but the way of doing it would be the same.

Retrofit Layer

According to Retrofit documentation:

Because we want to get the code response, we expect a Response object. Retrofit is going to call onNext (with the Response object) and onComplete when it finishes. If there’s an error, it will call onError.

APIService Layer

The APIService is in charge of making the API request, handling the errors we could get, parsing the registration response and processing that response. The UserAuthenticationRequestManager will call the register method with the RegistrationRequest object as a parameter.

Because it would be nice to know if we are making a network request, we can create a boolean attribute in this class to know if we’re requesting registration or not. That’s why, when something subscribes, because we’re going to fire the request, we set that flag to true. We can do it in doOnSubscribe method.

This is the method we call in doOnError. As you can see, we cast the Throwable instance to a RetrofitError instance and we get the response code. As you can see, we can throw different exceptions here. Why should we use it? Probably, in the Subscriber we want to handle different errors in different ways; so, the way we can do it is throwing different exceptions depending on the error and the Observable we’re in.

You can realise that we set the isRequestingRegistration flag to false, this is because onComplete is not going to be called after onError.

With the previous piece of code we can handle all the different errors. Now, we’ll focus on the response. As we said before, we’re going to get a Response object, we have to get the RegistrationResponse from the body. This is not always useful, do this if you need it. It can be helpful when depending on the successful response, you need to parse something different. For example, if I get a 200 I have to parse the response to a RegistrationResponse; however, if I get a 202, maybe I have to parse the response to a RegistrationWithMobilePhoneResponse.

Why do we return another Observable? We received a Response object from Retrofit, but what we want to emit now is a different object. We want to emit the RegistrationResponse object. We need to modify the observable, so we receive an Observable<Response> and we convert it to an Observable<RegistrationResponse>. We can do it returning an Observable which just emits one item, we can use Observable.just(). Observable.just() emits the item and calls onComplete when it finishes, it’s exactly what we want. If something is wrong, we can always return an Observable.error with the proper exception.

The way of doing this with RxJava is with the flatMap operator. We execute the flatMap operator over the original Observable to create another one.

The code below shows how you can parse the response from Retrofit.

Now that we have the RegistrationResponse, we can process it and apply the logic we need to. In our case, let’s say that we want to store in our AuthenticationManager the userID. We call this method in doOnNext because it’s where Retrofit sends the response to.

That’s it. We don’t have to do anything else, this class does everything we want it to do. If you call the method, you will fire a network request which will return an Observable<RegistrationResponse>.

RequestManager Layer

The RequestManager is going to prepare the data for the request and link the different requests we have to do. For this example, we need to register and if the registration was successful, we want to log the user in to the app. For that, we have to concatenate different requests: registration and login.

The LoginAPIService works exactly as RegistrationAPIService does: it will receive a LoginRequest and will return an Observable<LoginResponse> if everything was alright.

The way of concatenating the different requests is with the flatMap operator again. Where’s the problem? The output of registration doesn’t not match with the input of the login retrofit call. For that, we have to modify the Observable we get from registration to be able to pass it and make the network request.

As we did before, we can use the flatMap operator to alter the Observable we receive. The method returns an Observable<LoginResponse> because the happy path of registration&login method returns a LoginResponse object. That means that the use was able to register and log in. We can see an example without using retrolambda:

Let’s change the course of history now. The example above show how to concatenate and process synchronously different network requests. Now, let’s try to process asynchronously different network requests. This means: I want to fire two different network requests, and only when they both come, I want to process the response. Observable.zip() works in this scenario.

The user is logged in. And we want to get the data. The problem is that, we need the list of games the user plays and his personal information. We want something like:

As we can see below, getUserPersonalData and getUserGames are methods which returns an Observable. We can combine them, or maybe we want one after another, or maybe we want to call them individually… If we have different methods returning Observables, we can do with them whatever we want. Therefore, as an example, we could fire the registration request and the getUserData request at the same time. I know this does not make any sense at all, but it is possible. What I want you to realise is that you can combine, concatenate and treat Observables as you want.

You get a stream of data from an Observable. With that stream you can do whatever you want. If your method returns an Observable, you can reuse it for different purposes.

Because you can reuse them, if at some point you just want to call registration, you can create a method called registration and call it individually. But you can also create the method we saw before and call registrationAndLogin method which uses the previous registration method.

The method getUserGames works exactly as getUserPersonalData (see image), so at this point, we can call getUserGames individually, or if you want to get both together you can user getUserData.

ViewModel Layer

This layer is probably the trickiest one. Why? Do you remember the tips we talked about before? It turns out that:

If you just subscribe in the View layer, if the View goes to the background and you unsubscribe from the Observable, it will cancel the request. So… we don’t unsubscribe in onPause, we just do it onDestroy and the view will still listen for the response, right? Not really! What if in the onError method you want to show a Dialog saying that login failed? You cannot show a Dialog when the app is in the background! Your app will crash. For that reason, we have to call unsubscribe in OnPause method.

That means, that the ViewModel has to subscribe to the Observable which the RequestManager returns, but we want the same response to be propagated to our View just when it is listening for it. Answer? Subjects!

The Subject will propagate to its subscriber what it gets from the Observable it is subscribed to.

We have to convert the ViewModel in a Subject, that means we need a Subject in our ViewModel. We’ll need at least one per method we want to call in the RequestManagers.

How is it going to work?

  1. The view will subscribe to the Subject (ViewModel), for example onResume.
  2. The view will tell the ViewModel: I want to make this request (when the user taps the registration button, for example).
  3. The ViewModel will subscribe to the output of the method of the RequestManager, that’s going to fire the network requests (or just one, depending on the method). Retrofit will make the network request as soon as something subscribes to it. That would be something like: requestManager.register().subscribe(registrationSubject);
  4. Let’s say that the View is in the background.
  5. Retrofit returns an error. DoOnError methods are called. The Subject now has received an OnError call.
  6. The view is restored again and it is visible. Because we call subscribe to the Subject in onResume, that will register again. The Subject has a response queued up, and because now it has a listener it’s going to send it.
  7. The View receives onError and shows the proper Dialog.

Everything seems reasonable! But now we have to face another problem. Do you remember in the tips section when I said that each time you subscribe you have to create a new object? Unfortunately, it’s the same for subjects.

So before making another network request, we have to create a new object, that means we need a different Subject instance. You can take a look at the different types of Subject, for this example, we are going to use AsyncSubject because we just want the last result emitted by the Observable. We can provide the following code:

As you can notice, the refreshData method is going to subscribe for the method we saw before in the RequestManager which fires both getUserPersonalData and getUserGames requests asynchronously.

View Layer

The ViewModel layer and the View layer are very related to each other. We’ve already talked about what this layer is going to do. We will subscribe to the ViewModel subject in OnResume and will unsubscribe in OnPause.

When do we have to create a new Subject? We will want to create a new Subject when a response comes, in this way, if we want to make the same request again (Pull to Refresh, for example), we will be able to do it without any problems. We can include this piece of code onError and onComplete. See the Subscriber object:

You can see how in the onError method we process the different exceptions we throw during the different Observables (APIService, RequestManager, the ViewModel could potentially have thrown another one…). We call reconnectWithUserDataSubscriber in onCompleted and onError, and if you take a look, it does the same we do in subscribeForNetworkRequests but we call createUserDataSubject. When connecting, we get the previous Subject, when reconnecting, we create a new instance to be able to make the request again.

Check out the repository mentioned at the beginning of the article to understand it even better.

Conclusion

Everyone has heard about RxJava but not a lot of developers want to tackle it. I guess this is because it’s conceptually difficult and we’re not used to it when it comes to Android development. To be honest, it’s scary at the beginning but the more you know and read about it, the more fascinating it gets.

I learnt from different sources of information and not all of them work for whatever you want to do. This article comes from days and days of trial and error and research. It may not work for you, but hopefully it will make you understand few things better.

Remember that RxJava is a really powerful tool that can simplify your code. Is it worth it to do everything with it? Probably not, use it just when you need it.

I had that problem before, I wanted to use RxJava for a particular requirement in my project, but just because I wanted to use it (without any other reason): it was causing a lot of headaches, the code was more unreadable, there were complex unnecessary logic, etc. Result? I got rid of RxJava for that.

You can combine RxJava with other libraries such as: Otto (for event bus communication). Use it wisely and it will solve most of your problems.

Other articles

If you’re interested in these topics, I show how to make the ViewModels lifecycle aware in this article.

And how to survive configuration changes in this other one.

Thanks for reading,

Manuel Vicente Vivo

--

--