Parallel Multiple Network Calls Using Kotlin Coroutines
- Authors
- Name
- Amit Shekhar
- Published on
We can make multiple network calls in parallel using Kotlin Coroutines by starting each call with async, and then calling await() on each of them to get the results when both are done.
In this blog, we will learn how to make multiple network calls in parallel using Kotlin Coroutines.
I am Amit Shekhar, Founder @ Outcome School, I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.
I teach AI and Machine Learning, and Android at Outcome School.
Join Outcome School and get a high-paying tech job:
Let's get started.
I will be using this project for the implementation part. If you have not gone through the project, you should go through it and then come back. The project follows a basic MVVM Architecture for simplicity. You can find the complete code for the implementation mentioned in this blog in the project itself.
We will take the example of ParallelNetworkCallsViewModel which is present in the project.
Basically, this ParallelNetworkCallsViewModel is a ViewModel that is associated with ParallelNetworkCallsActivity which triggers the ViewModel to fetch the list of users to render into the UI. The ParallelNetworkCallsViewModel, then asks the data layer for the list of users using the ApiHelper. The ViewModel makes the two networks in parallel which are as getUsers and getMoreUsers. As you can see below, the ViewModel uses the Kotlin Coroutines and LiveData.
class ParallelNetworkCallsViewModel(
private val apiHelper: ApiHelper,
private val dbHelper: DatabaseHelper
) : ViewModel() {
private val uiState = MutableLiveData<UiState<List<ApiUser>>>()
private val exceptionHandler = CoroutineExceptionHandler { _, e ->
uiState.postValue(UiState.Error("exception handler: $e"))
}
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch(exceptionHandler) {
uiState.postValue(UiState.Loading)
val usersFromApiDeferred = async { apiHelper.getUsers() }
val moreUsersFromApiDeferred = async { apiHelper.getMoreUsers() }
val usersFromApi = usersFromApiDeferred.await()
val moreUsersFromApi = moreUsersFromApiDeferred.await()
val allUsersFromApi = mutableListOf<ApiUser>()
allUsersFromApi.addAll(usersFromApi)
allUsersFromApi.addAll(moreUsersFromApi)
uiState.postValue(UiState.Success(allUsersFromApi))
}
}
fun getUiState(): LiveData<UiState<List<ApiUser>>> {
return uiState
}
}
The above code makes both the network calls in parallel.
Now, let's try to understand how it is doing the two background tasks in parallel using Kotlin Coroutines.
Here if you notice, we have used the async{} which returns an instance of Deferred<T>, which has an await() function that returns the result of the coroutine like we have future in Java in which we do future.get() to the get the result.
Here, it makes both the network calls in parallel and await for the results.
The key point here is to launch two coroutines to do the two network calls in parallel. 1 coroutine for 1 task.
A quick note for you
No matter which tech domain you work in, get familiar with these topics:
- LLM
- RAG
- MCP
- Agent
- Fine-tuning
- Quantization
We put it all together in one video:
AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization
No need to stop reading - bookmark it and watch later when you get time. Future you will thank you.
Now, let's get back to the topic.
We have two options to do so either by using launch or async.
In our case, as we needed to get the result back from the tasks, we used async.
Similarly, we can do any type of background tasks in parallel using Kotlin Coroutines.
Stay updated: Subscribe to our newsletter to get our latest AI and Machine Learning blogs straight to your inbox.
Let's take another example.
Suppose we have two functions as below:
doLongRunningTaskOne()doLongRunningTaskTwo()
private suspend fun doLongRunningTaskOne(): Int {
return withContext(Dispatchers.Default) {
// your code for doing a long running task
// Added delay to simulate
delay(2000)
return@withContext 10
}
}
private suspend fun doLongRunningTaskTwo(): Int {
return withContext(Dispatchers.Default) {
// your code for doing a long running task
// Added delay to simulate
delay(2000)
return@withContext 10
}
}
In this case, as we need to get the result back from the tasks, we will use async to launch the coroutine.
So, we can run the two tasks in parallel using Kotlin Coroutines like below:
fun startLongRunningTaskInParallel() {
viewModelScope.launch {
val resultOneDeferred = async { doLongRunningTaskOne() }
val resultTwoDeferred = async { doLongRunningTaskTwo() }
val combinedResult = resultOneDeferred.await() + resultTwoDeferred.await()
}
}
Let's take another example, suppose we have two functions that do the task and do not return anything.
private suspend fun doLongRunningTaskOne() {
withContext(Dispatchers.Default) {
// your code for doing a long running task
// Added delay to simulate
delay(2000)
}
}
private suspend fun doLongRunningTaskTwo() {
withContext(Dispatchers.Default) {
// your code for doing a long running task
// Added delay to simulate
delay(2000)
}
}
In this case, as we do not need to get the result back from the tasks, we will use launch to launch the coroutine.
So, we can run the two tasks in parallel using Kotlin Coroutines like below:
fun startLongRunningTaskInParallel() {
viewModelScope.launch {
launch { doLongRunningTaskOne() }
launch { doLongRunningTaskTwo() }
}
}
This way, we are able to run two tasks in parallel.
You can find the end-to-end implementation in this project.
To master parallel network calls, Retrofit, OkHttp, MVVM Architecture, and the NewsApp project hands-on, check out the Android Program by Outcome School.
Frequently Asked Questions
Should we use launch or async to run tasks in parallel?
It depends on whether we need the result. If we need the result back from the tasks, we use async. If the tasks do not return anything, we use launch. Both can run two background tasks in parallel.
What does async return in Kotlin Coroutines?
async returns an instance of Deferred, which has an await() function that returns the result of the coroutine. It is similar to a future in Java, where we call future.get() to get the result.
How many coroutines do we need to make two network calls in parallel?
We need two coroutines. The key point is to launch one coroutine for one task. So, for two network calls, we start two coroutines and then wait for both results.
How are errors handled in the parallel network calls example?
The example uses a CoroutineExceptionHandler passed to viewModelScope.launch. If an exception occurs, the handler posts an error state to uiState with the exception message.
That's it for now.
Thanks
Amit Shekhar
Founder @ Outcome School
You can connect with me on:
Follow Outcome School on:
