How to make complex requests simple with RxJava in Kotlin

It is a common problem in Android development when your API is not sending you exactly the same data, what you want to show in your views, so you need to implement more complex requests. Possibly your app needs to make multiple requests, that wait for each other, or call multiple requests after the previous one finished. Sometimes you even need to combine these two approaches. This can be challenging in plain Java and will often result in unreadable code, what is also painful to test.

Today I’m going to show you in a simple example how this can be achieved in a clean way using RxJava. The example is written in Kotlin, what makes the code more concise and easy to read. If you are completely new to RxJava or Kotlin, I suggest you catch up on the basics. There are some great resources here as well.

Let’s see what do we want to achieve

We will use the StackOverflow public API to request the details of a specific user, which consist of the users top 3 questions, top 3 accepted answers, and top 3 questions the user has favorited. The feature should look like this:

If we want to achieve this behavior, we need to the make 3 separate requests to the API. Since the requests doesn’t depend on each other, we will get the best results if we execute them in parallel and then combine their results. We also need to make one more request, because when we are requesting the answers, the response doesn’t contain the question belonging to that answer. In the following graph you can see how our requests will look like.

To make it simpler, I won’t explain the code and the architecture of the whole app. We will only implement the UserRepository class, which provides the data for the presenter. You can find the complete source code in this Github repository, if you want to look at the rest of the code.

Let’s do some coding

We are going to implement the getDetails method in the UserRepository. This method provides the data for the DetailPresenter about the details of a user. Here is how it looks like at the beginning:

You may wonder what is the Single.create method doing. It is just there so the app could be built successfully. It creates a Single, what emits an empty DetailsModel. We are using Single instead of Observable, because it’s better for our use-case.

Single is similar to Observable, the difference is that it always emits exactly one value or an error. That is exactly what we need for a network call.

If you want to build the project and see what happens, or follow the example while coding it yourself you can check out this commit:

Using the zip operator to combine the results of multiple requests

First we implement the combination of the 3 requests. We will use the zip operator from RxJava. The ReactiveX documentation says the following about the zip operator:

Combine the emissions of multiple Observables together via a specified function and emit single items for each combination based on the results of this function

So what does this mean exactly? It takes one item from each Observable, and applies a function to them, then emits the result. In our case it’s even simpler, because Single only emits one item, so we just specify a function to transform the individual items into one.

This seems pretty simple, right? The zip function’s first three arguments are the results of the Retrofit requests. The fourth one is a lambda expression, that has 3 parameters. Those have the same types as the responses. The thing we need to do in the lambda is to apply some operations on the parameters to create our DetailsModel.

Using the Kotlin Collections API to create our DetailsModel

I think one of the best things in Kotlin is its Collections API. It provides a lot of functions, that you can use to manipulate collections. Let’s look at some of them, while implementing the createDetailsModel method:

  • take: This function is the most straightforward. It takes an Int parameter, and returns the first n elements of the collection. We use this, because we only want to show the first 3 items in each section.
  • filter: As its name says, this function filters out specific items from the collection by a given predicate. Its only argument is a lambda, that receives the item and returns a Boolean. If it returns true, the item will be included in the collection. The lambda expression in the snippet is the same as this: answer: Answer -> answer.accepted. If we only have one parameter in the lambda, we can omit its declaration, and use the it keyword instead.
  • map: With the map function we can apply a transformation to a collection. In this example we transform the Answer objects to AnswerViewModel objects. The transformation is simple here, we just create AnswerViewModel with the right fields of Answer. The reason we need this is that the Answer object we receive from the service doesn’t contain the title of the question, which the answer belongs to. Right now we just set it to “TODO” and deal with it soon.

One final thing to note about this. When we are chaining these functions, we need to think about the order carefully. Let’s assume the first 3 answers we receive from the service are not accepted. If we change the filter and take functions, we won’t get any items in the end. Also if we change the take with map, the transformation will be applied to every element in the list, which is unnecessary.

The following commit contains the above changes:

Get the questions belonging to the answers

If we want to show the titles of the questions belonging to the answers, we need to make an other request after we received the answers. This is usually done with the flatMap operator in RxJava. The flatMap documentation for Single states the following:

Returns a Single that is based on applying a specified function to the item emitted by the source Single, where that function returns a SingleSource.

Let’s simplify this with an example:

.flatMap { answerListModel: AnswerListModel ->
questionService.getQuestionById("1234;2345;3456") }

As you can see flatMap receives a lambda, which uses the emitted item as a parameter from the original Single. The return value of the lambda is a new Single, that can emit a different type of item, then the original one.

In the above example we are requesting specific questions by their id, but this is not enough. We need to get the question ids from the answers, then request the questions, and finally apply some transformations to the result to create a list of AnswerViewModel objects. The code snippet below shows how to achieve this.

Let’s focus on the getAnswers method, and the other two methods it is using, the rest of the code is almost the same as before.

The getAnswers method looks similar to the flatMap example before, but in this case we are not making the request here, instead we call a method, where we construct and call our request. Here we use again the Collections API to transform the list of answers into a String of ids concatenated by the “;” character (This is the format StackOverflow needs).

The new thing here is the joinToString function. We can use this on any collection to make a single String from its elements.

After we have the ids, we are requesting the questions. This part of code might look confusing.

val questionsListModel = questionService.getQuestionById(ids)

return questionsListModel
.map { questionListModel: QuestionListModel? ->
addTitlesToAnswers(answers, questionListModel?.items ?: emptyList()) }

Because of the map operator you might think questionsListModel is a collection, but it’s not. It’s a Single, like the result of every request in our example. There is also a map operator in RxJava, what works like the map in the Collections API. It can apply a transformation to the item emitted by the Single. So we are applying a transformation by calling the addTitlesToAnswers method.

The addTitlesToAnswers method is another good example of the power of the Collections API. We also use an other Kotlin concept here. Instead of declaring the lambda parameter as an Answer type we use destructing declaration. If you’re not familiar with it, you can read about it here.

And now we have our DetailsModel constructed from multiple requests. You can check the full code in this commit:

There is always space for optimization

If you look at the last snippet carefully, maybe you notice we made a mistake. It’s not critical, but it can slow down our request. We are requesting the questions for every answer, and in the end we just only take the first 3 answers. It would be better to only request those 3 questions. This little optimization made the request approximately 1 second faster on my phone. This change can be found in this commit:


Although the learning curve for RxJava is steep, it is worth the time to learn the basics at least, especially the concepts that are useful in Android development. Some of these concepts are the things discussed above. Combining these with the Kotlin Collections API can really help you simplify your data flow, but if you are still using Java, this can be a great addition to your codebase too.

Thanks for reading my article. If you have any questions or suggestions, feel free to leave a comment. If you are interested in other Kotlin examples, you can check out the Github repository of the project.

If you found this helpful, don’t forget to click the💚 below to make it reach more people.