6

We have a list of operations that is async in nature. We want to finish all the operation lets say and want to do another task. I am totally new to Kotlin Coroutines concept and unable to achieve this task. I searched out a lot on the internet but since I have no overall experience with kotlin coroutines or another async service of kotlin to do this. Anyone has any idea how to achieve this task will be very helpful. Lets say I have 20 elements in the list and I want to do an operation on each element which is async in nature.

      response.data?.let { dataArray ->

                if (dataArray.isNotEmpty()) {
                    it.forEach {
                        it.unpair().done{
                           // Async call.  
                       }
                    }
              // All async operation completed do another task.
                    
                } else {
                    // Array is empty.
                }
            }
Wisal
  • 153
  • 2
  • 10
  • 1
    Does this answer your question? [Kotlin Coroutines - How to block to await/join all jobs?](https://stackoverflow.com/questions/54719864/kotlin-coroutines-how-to-block-to-await-join-all-jobs) – Nicolas May 12 '20 at 19:53
  • @Nicolas thank you i will check this . – Wisal May 12 '20 at 21:35

2 Answers2

8

I think a clean way to do an async task on each item in a list is to use map and then awaitAll. The resulting list contains all your results, after the coroutine resumes.

From inside a coroutine:

val unpackedData = results.data.orEmpty().map {
        async { 
            it.unpair().done() 
            // I don't really know what type of object this is, but you can do anything in 
            // this block and whatever the lambda eventually returns is what the list will 
            // contain when the outer coroutine resumes at the awaitAll() call
        }
    }.awaitAll()
// Make other calls here. This code is reached when all async tasks are done.

The orEmpty() function is a handy way to convert a nullable list into a non-nullable one to make the code simpler by removing branches. Sometimes it's not really applicable, but often you can eliminate nested if statements or early returns. Like if you iterate your resulting data and it's empty, that may be perfectly fine.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
1

Make sure you are running this within a coroutine scope

val requests = ArrayList<Deferred<Unit>>()
val dataArray = response.data ?: return

dataArray.forEach { data ->
  data.unpair().done {
    // YOUR METHOD starts running immediately
    requests.add( async { YOUR METHOD } )
  }
}

// Waits for all YOUR METHOD's to finish
requests.awaitAll()
PenguinDan
  • 904
  • 7
  • 15
  • Daniel Kim thank you for your time and help.where should I put the code for another task which I want to do after completion of this process. – Wisal May 12 '20 at 21:34
  • @mtg It can go right under the `requests.awaitAll()` call – PenguinDan May 12 '20 at 21:36
  • what should i put in place of YOUR METHOD in this block requests.add( async { YOUR METHOD } ) – Wisal May 12 '20 at 21:49
  • Whatever code you need to run asynchronously without blocking, whether it is another function, or the code that you need to run for each data object. the `awaitAll()` method will block for you until all of those calls finish. – PenguinDan May 12 '20 at 22:07