---
title: "Handle Complex Network Call on Android with Kotlin Coroutine + Retrofit 2 in MVVM"
description: "In this article, I’ll demonstrate how to use coroutine in order to - Chain multiple network request - Create parallel network requests and process the responses when all of them are finished."
canonical: https://oozou.com/blog/handle-complex-network-call-on-android-with-kotlin-coroutine-retrofit-2-in-mvvm-9
locale: en
date: 2018-07-26
author: "OOZOU Team"
---

# Handle Complex Network Call on Android with Kotlin Coroutine + Retrofit 2 in MVVM

> In this article, I’ll demonstrate how to use coroutine in order to - Chain multiple network request - Create parallel network requests and process the responses when all of them are finished.

Published: 2018-07-26 · Author: OOZOU Team (Engineering) · 6 min read

When you’ve been working with some Android applications, you may encounter the scenario where you have to make multiple network requests such as chained or parallel requests and combine their results.

To handle the mentioned scenario, some might say “let’s use **RxJava**!!!” but… come on the learning curve of RxJava is no joke, at least for me.

Don’t get me wrong, it doesn’t mean that I hate RxJava. RxJava is a really powerful library but **Kotlin coroutine** seems to suit my existing app architecture better.

In this article, I’ll demonstrate how to use coroutine in order to

- Chain multiple network request
- Create parallel network requests and process the responses when all of them are finished.

I won’t get into much detail about how coroutine works but I’ll focus on using it in action.

**Introduction**

Before we begin I would like to briefly address the concept and the commonly used functions in Coroutine.

**Brief Concept**

Writing the code asynchronously has always been a pain for me, especially when dealing with complex network requests. It’s hard to write easy-to-read code and sometimes you may end up with a lot of callbacks in your code. **Therefore, one of the purposes of Kotlin Coroutine is to help us write a neater code when working with asynchronous programming.**

Here is what written in Kotlin Official document.

> _Coroutines simplify asynchronous programming by putting the complications into libraries. The logic of the program can be expressed sequentially in a coroutine, and the underlying library will figure out the asynchrony for us._

**Launch and Async**

launch and async are the most commonly used **Coroutine builder.**

Here is the official definition.

> **_launch_**_\- Launches new coroutine without blocking current thread and returns a reference to the coroutine as a_ [_Job_](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html)_. The coroutine is canceled when the resulting job is_ [_cancelled_](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html)_.
> _**_async_**_\- Creates new coroutine and returns its future result as an implementation of_ [_Deferred_](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html)_. The running coroutine is canceled when the resulting object is_ [_cancelled_](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html)_._

Take a look at this piece of code as an example.

```kotlin
launch {
  delay(2000)
  println("launch block")
}

val result: Deferred<String> = async {
  delay(3000)
  "async block"
}

println(result.await())
```

From the example, the difference between **launch** and **async** is that **async** can return the future result which has a type of **Deferred\<T\>**, and we can call **await()** function to the **Deferred** variable to get the result of the Coroutine while launch only executes the code in the block without returning the result.**Coroutine Scope**

Coroutine Scope defines a scope for coroutines. Every **coroutine builder** (like [launch](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html), [async](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html), etc) is an extension on [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.md). When the scope dies, the Coroutines inside will be out of the picture too. Fortunately, Android **lifecycle-viewmodel-ktx** provides a really easy way to get a **Coroutine Scope** in the ViewModel. I will show you how to do so later.

**Let’s start!**

**Dependencies**

Here are the things you need to add to your build.gradle

```groovy
dependencies {
    // Retrofit
    implementation "com.squareup.retrofit2:retrofit:$latestRetrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$latestRetrofitVersion"

    // OKHttp
    implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
    implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
    implementation "com.squareup.okhttp3:okhttp-urlconnection:$okHttpVersion"

    // Kotlin & Coroutines
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"

    // For Viewmodel to work with Coroutine
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleViewmodelKtxVersion"

}
```

**API Interface**

Let's create an API interface that defines the API path we going to deal with.

Normally, when defining the path in API interface we’ll do something like this right?

```kotlin
interface SomeApi {    
    @GET("path1/")  
    fun getObject1(): Call<Object1>

    @GET("path2/")   
    fun getObject2(): Call<Object2>   

    @GET("path3/{id}")   
    fun getObject3(@Path("id") objectId : String): Call<Object3> 
}
```

However, to make it work with Coroutine, we may do it this way.

```kotlin
interface SomeApi {    

   @GET("path1/")   
   suspend fun getObject1(): Response<Object1>

   @GET("path2/")
   suspend fun getObject2(): Response<Object2>    

   @GET("path3/{id}")   
   suspend fun getObject3(@Path("id") objectId : String): Response<Object3> 
}
```

Basically, we made our API interface’s functions as suspend function so that we can use them asynchronously later on.
**Providing Retrofit API**

```kotlin
object Api {
    fun getApiService(): SomeApi {
        val gson = GsonBuilder().create()
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(provideOkHttpClient(provideLoggingInterceptor()))
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build().create(SomeApi::class.<em>java</em>)
    }

    private fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
        val b = OkHttpClient.Builder()
        b.addInterceptor(interceptor)
        return b.build()
    }

    private fun provideLoggingInterceptor(): HttpLoggingInterceptor {
        val interceptor = HttpLoggingInterceptor()
        interceptor.<em>level </em>= HttpLoggingInterceptor.<em>Level</em>.<em>BODY
        </em>return interceptor
    }
}
```

**Providing Repository**

```kotlin
class SomeRepository(val apiService: SomeApi) {

    suspend fun getObject1(): Response<Object1> = apiService.getObject1()

    suspend fun getObject2(): Response<Object2> = apiService.getObject2()

    suspend fun getObject3(objectId : String): Response<Object3> = apiService.getObject3((objectId)

}
```

**Chaining network requests**

Let’s say we have to create two network requests in a row and we have to use the result from the first request to create the second one.

In our example, suppose the path of endpoint `path3/{id}` depends on the result of the endpoint `path1/`

The code may look like this.

```kotlin
class SomeViewModel(
    private val repository: SomeRepository
) : ViewModel() {
    fun chainingRequest() {
        viewModelScope.launch <strong>{
            </strong>val object1 = repository.getObject1().body()
            val object3 = repository.getObject3(object1.<em>id</em>).body()
            processObject3(object3)
        <strong>}
    </strong>}
}
```

**Create parallel network requests**

Suppose we have to create two requests at the same time and process the results when the responses of both endpoints have returned. In our case, let’s call the endpoint **/path1** and **/path2** parallelly. The code going to look like this.

```kotlin
class SomeViewModel(
    private val repository: SomeRepository
) : ViewModel() {

    fun parallelRequest() {
        viewModelScope.launch {
            try {
                val getObject1Task = async { apiService.getObject1() }
                val getObject2Task = async { apiService.getObject2() }

                processData(getObject1Task.await().body(), getObject2Task.await().body())
            } catch (exception: Exception) {
                Log.e("TAG", exception.message)
            }
        }
    }
}
```

Let’s break it down.

- The requests happen at `val getObject1Task = async { apiService.getObject1() }` and `val getObject2Task = async { apiService.getObject2() }`. Although the code is written in the sequential, the requests perform asynchronously.
- Then we pass the results of both requests to be process in successHandler. The results are obtained by **getObject1Task.await().body()** and **getObject2Task.await().body()**- The **processData** will only be called only when both **getObject1Task** and **getObject2Task** are finished.

# Conclusion

Overall, I’m impressed by how coroutine helps us simplify asynchronous programming. Moreover, It gets us out of the callback hell and makes it easier to handle complex network requests. I think there is no excuse not to give coroutine a try now.

# Source

- [https://medium.com/@andrea.bresolin/playing-with-kotlin-in-android-coroutines-and-how-to-get-rid-of-the-callback-hell-a96e817c108b](https://medium.com/@andrea.bresolin/playing-with-kotlin-in-android-coroutines-and-how-to-get-rid-of-the-callback-hell-a96e817c108b)
- [https://proandroiddev.com/kotlin-coroutines-handling-concurrency-like-a-pro-retrofit2-coroutines-31cd0611fd91](https://proandroiddev.com/kotlin-coroutines-handling-concurrency-like-a-pro-retrofit2-coroutines-31cd0611fd91)
- Kotlin for Android Developers book by [Antonio Leiva](https://medium.com/u/a199eb0fa9a0?source=post_page-----30a6cd1e0189----------------------)([https://antonioleiva.com/kotlin-android-developers-book/](https://antonioleiva.com/kotlin-android-developers-book/))

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
