Ali Khoshraftar
Ali Khoshraftar

Reputation: 542

Kotlin coroutines await for 2 or more different concurrent requests

I'm using kotlin coroutines to get responses from server in android with viewmodel. The problem is that i want to get two different requests responses to update ui but wanna execute them concurrently and wait for both of them to finish. then update the ui with all of the result received. If using async and await after each request it will execute one by one and it's not concurrent and if using map of requests and awaitAll(), i can't handle multiple data types (data classes) because the data types of two requests are different. It could be more that two requests. What can i do for this situation ?

val job = viewModelScope.launch {

        val a = async { firstUseCase.execute() }.await()
        val b = async { secondUseCase.execute() }.await()
 }

Upvotes: 8

Views: 17209

Answers (2)

Anoop M Maddasseri
Anoop M Maddasseri

Reputation: 10529

You could use async coroutine builder along with a parallel map to run dynamic bg works parallel and suspend further execution until all the results are available -

import kotlinx.coroutines.*

fun main() {
  runBlocking<Unit>
     {
       val smoothie = prepareSmoothie()
       println("prepareSmoothie | Smoothie prepared with: $smoothie")
     }
}

private suspend fun addIngredient(index: Int, item: String): String {
  println("prepareSmoothie | addIngredient: $item")
  delay(index.times(3_000).toLong())
  println("prepareSmoothie | addedIngredient: $item")
  return "$item"
}

private suspend fun prepareSmoothie(): List<String> {
  println("prepareSmoothie | Go On")
  println("++++++++++++++++++++++")
  return runBlocking {
      listOf("Fruits", "Grains", "Flavor boosters", "Ice").mapIndexed { index, item ->
        async {
          addIngredient(index, item)
        } .map { it.await() }
   }
}
  
Result:
  
prepareSmoothie | Go On
++++++++++++++++++++++
prepareSmoothie | addIngredient: Fruits
prepareSmoothie | addIngredient: Grains
prepareSmoothie | addIngredient: Flavor boosters
prepareSmoothie | addIngredient: Ice
++++++++++++++++++++++
prepareSmoothie | addedIngredient: Fruits
prepareSmoothie | addedIngredient: Grains
prepareSmoothie | addedIngredient: Flavor boosters
prepareSmoothie | addedIngredient: Ice
++++++++++++++++++++++
prepareSmoothie | Smoothie prepared with: [Fruits, Grains, Flavor boosters, Ice]

Upvotes: 4

Glenn Sandoval
Glenn Sandoval

Reputation: 3745

You just need to start every request first calling async in order to get a concurrent behavior and then await for all of them no matter if you do it individually one after another or all of them at once with awaitAll.

Individually:

viewModelScope.launch {
    val a = async { firstUseCase.execute() }
    val b = async { secondUseCase.execute() }

    val resA = a.await()
    val resB = b.await()

    //Use results 'resA' and 'resB' here
}

Or with awaitAll:

viewModelScope.launch {
    val a = async { firstUseCase.execute() }
    val b = async { secondUseCase.execute() }

    val (resA, resB) = awaitAll(a, b)

    //Use results 'resA' and 'resB' here
}

Upvotes: 30

Related Questions