首页 > 解决方案 > 迭代协程并等待结果

问题描述

我有一种情况,我需要调度仅在运行时才知道的不确定数量的网络调用。每个调用都会返回一个列表。当每个都返回时,我需要将这些列表合并到一个合并列表中。我正在使用协程来做到这一点。

我遇到的问题与我不知道应用程序需要进行多少网络调用有关。为了解决这个问题,我使用循环在运行时迭代调用列表:

private suspend fun fetchData(params: List<Interval>): List<Item> {

    val smallLists = mutableListOf<Deferred<List<Item>>>()
    val merged = mutableListOf<List<Item>>()

    for (index in 0 until params.size) {
        val param = params[index]
        // loop stop iterating after this call is dispatched
        smallLists[index] = CoroutineScope(Dispatchers.IO).async {
            fetchList(param)
        }
    }

    for (index in 0 until smallLists.size) {
        merged[index] = smallLists[index].await()
    }

    return merged.flatMap { it.toList() }
}

private fun fetchList(param: Interval) : List<Item> {
    return dataSource.fetchData(param)
}

这段代码发生的事情是它进入了第一个循环。params清单是正确的。它分派第一个查询,然后这个查询返回(我可以通过 Charles 代理看到这个)。

但这就是一切都死去的地方。应用程序对网络响应不做任何事情,循环终止(即没有第二次循环迭代)。

我知道其他一切都完好无损,因为我有一个不包括循环的替代版本。它只执行两个查询,等待它们的结果,然后返回组合列表。它工作正常,除了它不会处理动态运行时情况:

private suspend fun fetchData(params: List<Interval>): List<Item> {        
    val list1 = CoroutineScope(Dispatchers.IO).async {
        fetchList(params[0])
    }

    val list2 = CoroutineScope(Dispatchers.IO).async {
        fetchList(params[1])
    }

    return list1.await() + list2.await()
}

这里可能是一个简单的解决方案,但我没有看到。任何帮助表示赞赏。

标签: androidkotlinkotlin-coroutines

解决方案


这是不正确的:

smallLists[index] = CoroutineScope(Dispatchers.IO).async {
        fetchList(param)
    }

smallLists是空的,所以你不能访问 index index。改成这样

smallLists.add(CoroutineScope(Dispatchers.IO).async {
        fetchList(param)
    }
)

请注意,您也可以调用awaitAll()您的 s 列表async,以简化您的代码:

private suspend fun fetchData(params: List<Interval>): List<Item> {

    val smallLists = mutableListOf<Deferred<List<Item>>>()

    for (index in 0 until params.size) {
        val param = params[index]
        // loop stop iterating after this call is dispatched
        smallLists.add(CoroutineScope(Dispatchers.IO).async {
            fetchList(param)
        }
    })

    val merged = smallLists.awaitAll()
    return merged.flatMap { it.toList() }
}

推荐阅读