Ways to hit multiple API calls efficiently with Kotlin Coroutine threads?
By Sobhana kr — “Optimistic Quoter”
Let’s Consider a Situation, where call1 is expecting an id to make call2 with the fetched id from call1 response and based on the response from call2, call3 conditions, and params will be altered.
call 1 → call2 with id -> call3
How generally multiple dependant parallel calls are made.
Usually, the First call will be made and once we get the response, and manipulate the data then the next call will be made.
viewModelScope.launch {
val data1Response:BaseResponse<Data1>?
try{
val call1 = repository.getAPIcall1()
}
catch (ex: Exception) {
ex.printStackTrace()
}
processData(data1Response)
}
viewModel?.data1?.collect { dataResponse1 ->
repository.getAPIcall2()
}
viewModel?.data1?.collect { dataResponse2 ->
repository.getAPIcall3()
}
If we are fetching more than one API call. And each one is interdependent on other data. We need to sync up before data manipulation. Then Coroutines will be an optimized approach for us to asynchronously fetch data and wait for our expected outcome to do business logic.
To know about the basics of Kotlin Coroutines and its benefits refer https://medium.com/@krsobhana10/what-is-kotlin-coroutines-and-how-will-it-benefit-us-fb6072bbb313
To include Kotlin Coroutines in our project, First, we need to add the following dependencies in build.gradle file
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
}
To know about CoroutineScope and viewmodelScope refer https://medium.com/@krsobhana10/scopes-and-cancellation-of-coroutines-97a9a9333f8b which will be used in references.
Async will be expecting a response from the call. Here call1 will provide data that should be synced with call2 and so on. The data manipulation can be done with the fetched response. But it will have some wait time between each call. With awaitAll(), we can combinedly call for a list of APIs at a time.
viewModelScope.launch {
val data1Response:BaseResponse<Data1>?
val data2Response: BaseResponse<Data2>?
val data3Response: BaseResponse<Data3>?
val call1 = async { repository.getAPIcall1()}
val call2 = async { repository.getAPIcall2()}
val call3 = async { repository.getAPIcall3() }
try {
data1Response = call1.await()
data2Response = call2.await()
data3Response = call3.await()
} catch (ex: Exception) {
ex.printStackTrace()
}
processData(data1Response, data2Response, data3Response)
}
suspend fun fetchData() =
coroutineScope {
val mergedResponse = listOf(
async { getAPIcall1() },
async { getAPIcall2() }
)
mergedResponse.awaitAll()
}
It is similar to async-await. But it will have less overhead. Instead of withholding the main UI thread, withcontext will switch to a separate thread and perform the task. It will not have a wait time as async-await.
if runBlocking is added overlapping the withContext(), it will reverse the asynchronous and cancellable nature of Coroutines and blocks the thread. Until the particular task is done.
4 types of Dispatchers are there. IO, Main, Default, unconfined
viewModelScope.launch {
withContext(Dispatchers.Default) {
val apiResponse1 = api.getAPICall1()
val apiResponse2 = api.getAPICall2()
if (apiResponse1.isSuccessful() && apiResponse2.isSuccessful() { .. }
}
}
The third approach is slightly different and if we want two independent response and stitch it together to get a new response, then Zip Operator will help us to parallelly fetch the response.
repository.getData1()
.zip(repository.getData2()) { data1, data2 ->
return@zip data1 + data2
}
.flowOn(Dispatchers.IO)
.catch { e ->
..
}
.collect { it ->
handleSuccessResponse(..)
}
Out of these three approaches, when we want to call multiple parallel calls with wait time, async-await Approach will be suitable. When we want an even more efficient approach with thread switching, withcontext will be suitable. And to stitch two responses together and perform some data manipulation, Zip operator approach is suitable. Hope we learned about some Kotlin Coroutine multiple calls approaches and can follow some of them in our day-to-day use cases.
Author
Reviewed By
Editor
We at CaratLane are solving some of the most intriguing challenges to make our mark in the relatively uncharted omnichannel jewellery industry. If you are interested in tackling such obstacles, feel free to drop your updated resume/CV to careers@caratlane.com!
Leave a Reply