Завершение списка асинхронных вызовов в Котлине

У нас есть список асинхронных операций. Мы хотим завершить все операции, скажем так, и хотим выполнить другую задачу. Я совершенно не знаком с концепцией Kotlin Coroutines и не могу выполнить эту задачу. Я много искал в Интернете, но поскольку у меня нет общего опыта работы с сопрограммами kotlin или другим асинхронным сервисом kotlin, чтобы сделать это. Любой, кто знает, как решить эту задачу, будет очень кстати. Допустим, у меня в списке 20 элементов, и я хочу выполнить операцию с каждым элементом, который является асинхронным по своей природе.

      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.
                }
            }

person mtg    schedule 12.05.2020    source источник
comment
Отвечает ли это на ваш вопрос? Kotlin Coroutines - Как заблокировать ожидание / присоединение ко всем заданиям ?   -  person Nicolas    schedule 12.05.2020
comment
@Nicolas спасибо, я проверю это.   -  person mtg    schedule 13.05.2020


Ответы (2)


Убедитесь, что вы запускаете это в области сопрограммы

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()
person PenguinDan    schedule 12.05.2020
comment
Дэниел Ким благодарит вас за ваше время и помощь. Где мне разместить код для другой задачи, которую я хочу выполнить после завершения этого процесса. - person mtg; 13.05.2020
comment
@mtg Может идти прямо под вызовом requests.awaitAll() - person PenguinDan; 13.05.2020
comment
что я должен поставить вместо ВАШЕГО МЕТОДА в этом блоке requests.add (async {ВАШ МЕТОД}) - person mtg; 13.05.2020
comment
fun clearItems (dataArray: Array ‹Item›) = uiScope.launch {val requests = ArrayList ‹Deferred ‹Unit›› () dataArray.forEach {data - ›data.unpair (). done {// ВАШ МЕТОД запускается немедленно, запросы .add (async {// что я должен туда положить.})}} requests.awaitAll ()} - person mtg; 13.05.2020
comment
Дэниел Ким, ты здесь. любая идея, какую вещь я должен здесь поставить. - person mtg; 13.05.2020
comment
Какой бы код вам ни понадобился для асинхронного выполнения без блокировки, будь то другая функция или код, который вам нужно запустить для каждого объекта данных. метод awaitAll() будет заблокирован для вас, пока не завершатся все эти вызовы. - person PenguinDan; 13.05.2020

Я думаю, что простой способ выполнить задачу async для каждого элемента в списке - использовать map, а затем awaitAll. Полученный список содержит все ваши результаты после возобновления работы сопрограммы.

Изнутри сопрограммы:

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.

Функция orEmpty() - удобный способ преобразовать список, допускающий значение NULL, в список, не допускающий значения NULL, чтобы упростить код путем удаления ветвей. Иногда это не совсем применимо, но часто вы можете исключить вложенные операторы if или ранние возвраты. Например, если вы перебираете полученные данные, а они пустые, это может быть совершенно нормально.

person Tenfour04    schedule 13.05.2020