Making Network calls on Android with Retrofit + Kotlin’s Coroutines

Khalid Abdul Wahab
Hacktive Devs
Published in
8 min readApr 14, 2019

In recent years, the world of Android development has seen many changes. One of these changes is Kotlin’s Coroutines. Last year, the release of a stable version of Kotlin’s Coroutines saw a lot of movement from Rx Java.

In this article, we will be talking about how to combine Retrofit2 with coroutines when you are making networking calls on Android. I will be making use of News API to fetch the latest news in this example but you are free to make use of any API you want.

This article assumes that you know what Kotlin’s coroutines are. If you are not familiar with coroutines, you should through the official documentation before continuing.

I also strongly recommend this article for a better understanding of what coroutines are.

A quick recap of how Networking on android works.

Networking on android works in the following way:

First, your code makes an HTTP request to a URL or endpoint with proper headers, usually with authorization keys if required. Then, the request returns a response that will contain the content of the endpoint which is usually in JSON format. Finally, your code parses the result(JSON), gets the required value and stores them in a kotlin data class.

In this article, I will be using Okhttp for creating HTTP requests with the proper headers, Retrofit2 for making those requests and Moshi for parsing the response gotten from those requests. You are also free to use Gson for parsing the JSON response.

Let’s write some code!!

First of all, we will want to add the dependencies for all the libraries mentioned above to our project. We can go to our build.gradle file for the Module: app and add the following dependencies under the dependencies section.

You could be using any other API but if you are using news API, you will need to create an account and get an API key from the website. I would be using this key later.

After getting a valid API key from news API, you can test their endpoints and check their JSON responses. Below is an example of a JSON response from news API that gets news from Nigeria sorted by the date they were published.

You can easily convert the JSON into a Kotlin data class using the JSON to Kotlin converter plugin in Android studio. If you do not have the plugin, you can check it out here. After you have downloaded the plugin, you can right click on the package you want the data class to be located in your project, select New -> GenerateKotlinClassFile and paste your JSON in the dialogue that appears.

JSON to kotlin generator

You will also see a settings button on the dialogue that allows you to make various configurations to your data class depending on how you want your data class to look like. Below, you will see that I have selected Moshi under annotations because I am using Moshi to parse my JSON. You can select Gson or any other library you wish to use.

Click on generate and your data classes will be ready for you to use. Below are the data classes generated from the JSON above.

You can see that the structure of the data classes corresponds to the structure of the JSON. You can also remove variables that you do not need.

Before we move on, let us take some time to review the MVVM architecture.

MVVM architecture

Here, we can see that the repository tries to get data from the data source(in this case, News API), the ViewModel checks the repository for data and the activity observes the ViewModel via what we call LiveData. Check here if you are not familiar with these concepts already. We will not be implementing the full MVVM architecture in this article since our focus here is different but We’ll be using a few concepts mentioned here in future sections of the article.

Creating the ApiClient.

If we take a look at the URL( https://newsapi.org/v2/everything?q=Nigeria&sortBy=publishedAt&apiKey=******************), you will notice that the URL consists of

  1. The base URL(https://newsapi.org/)
  2. The path(v2/everything)
  3. The query parameters (q=Nigeria&sortBy=publishedAt&apiKey=******************)

The API client will help us in building this URL. These include using Okhttp to create HTTP requests, adding an interceptor that will allow us to add the API key as a query param to every request and creating our HTTP request and handler using retrofit. Let us see some code.

In the code above, you can see that we created an object and not a class because we want to call the functions and variables in the class without creating an instance of the class. The interceptor variable is going to help us add the API key as a query parameter to the URL, we then build a networking client using Okhttp and the interceptor. In the function getRetrofit(), we build the HTTP request using retrofit by adding the client we built earlier, adding the base URL of the endpoint, specifying that we are using MoshiConverter factory and also specifying the call adapter factory as the coroutineCallAdapeterFactory which is a Retrofit2 CallAdapter.Factory for Kotlin coroutine's type Deferred .We will see why this is useful soon. You can use this interceptor for multiple HTTP requests to different URL’s, Just make sure you change the base URL for each call. The last line uses the getRetrofit() function to create our NewsApiInterface. However, we do not have an API interface yet, do we? Let’s create one!

Creating the API interface.

The API interface will include functions that will make the API calls with query parameters where necessary. Note that we have made reference to this API interface in the API client which was talked about in the previous section.

In the above interface, we have created a function fetchLatestNewsAsync that is annotated with “@GET” from the retrofit2 library since we are getting data from the API. You could annotate with POST, PUT, etc depending on what endpoint you are consuming. We also added the query parameters in the URL and the path that we are going to. This will join up with the base URL so make sure that your spellings are correct. The most important thing to note about the function above is that it returns a deferred response and not just a response. When a function returns a deferred which is from the coroutine library, you can await the result of the function since the function is going to take some time to complete. If you have any other endpoints that make use of the same base URL specified in the API client, you can simply create a similar function with its own path and its own query parameters.

Time To Make the Network Calls!!

In order to make use of the classes above, we need to call them from somewhere. We could call them in our activity, fragment, repository or ViewModel. Let's do it the right way!

First, we create a sealed class to handle network response. It can either be a success with the results coming with it or failure with an exception

We then create a base repository class to handle the safe API calls.

Here, we have two suspending higher-order functions. They both take a suspending function that returns a response(This will be the JSON response from the API) and an error message that will be displayed when an error occurs and there is no response. The newsApiOutput() function will try to get a response from the API. if it is successful, then we call the success data class in our sealed class and pass in the content of the response. If it is a failure, we call the Error data class in our sealed class and pass in an IOException with the error message. We use this newsApiOutput() function in our safeApiCall() function and return the output.

We can now create a News repository or any other repository and extend this base repository class to make a safe API call.

Our NewsRepo class extends the Base repository class so that we can call its functions and it also takes in the News API interface as a parameter. Inside a suspending function getLatestNews() that returns a mutable list of articles, we call the safeApiCall function from the base repository. This will return the latest News, we can now get the articles and convert it to a mutable list. One thing to note here is that when we were passing in the parameters for the safeApiCall() function, we had to call the function in the API Interface and await the result, This is possible because the fetchLatestNews function is returning coroutine’s Deferred type.

Creating the ViewModel and The ViewModelFactory

The ViewModel is pretty simple, we just simply create a new Job. A job is the return type of coroutine’s launch function. We can use this Job to join or cancel any coroutine at any moment. We create a coroutine context and specify the dispatcher we want our job to use. Note that there are different types of dispatchers, make sure you select the right dispatcher for your use case. Dispatchers are coroutine contexts that specify the thread or threads that can be used by the coroutine to run its code. Here I am using the default dispatcher, If you were making this call in an activity or fragment, you may want to do this using the main dispatcher in that case. Inside the coroutine scope’s launch function, we are calling the getLatestNews() function from the repository. We have to call this function inside a coroutine scope because it is a suspending function and a suspending function can only be called inside a coroutine scope or inside another suspending function. The results from this call will be posted to newsLiveData as Live Data so that it can be observed by an activity or fragment.

The View Model factory is also pretty simple. We will be using it to instantiate our view model in the activity or fragment.

Final Step!!, The Activity

We can now go to our activity or fragment, create an instance of the view model and use it to call getLatestNews in the view model class. we would also call newsLiveData from the view model and observe it from our fragment.

That’s it!! We have been able to easily combine Kotlin’s coroutines with the retrofit2 library to handle network calls in android! This article only treated combining coroutines with Retrofit. In a real application, you will probably want to do more than that, i.e combine it with Room, add dependency injection, etc. I have an example repository here that implements the complete MVVM architecture using coroutines. All code samples for this article can be found here. Happy Coding!

--

--

Khalid Abdul Wahab
Hacktive Devs

Android developer | Backend web developer. I love to share the little i know