迭代协程并等待结果

时间:2019-07-02 17:13:18

标签: android kotlin kotlin-coroutines

我遇到一种情况,我需要调度仅在运行时才知道的不确定数量的网络调用。每个呼叫都会返回一个列表。返回每个列表时,我需要将这些列表合并到一个合并的列表中。我正在使用协程执行此操作。

我遇到的问题与以下事实有关:我不知道该应用程序需要进行多少次网络通话。为了解决这个问题,我使用循环在运行时遍历调用列表:

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()
}

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

1 个答案:

答案 0 :(得分:2)

这是不正确的:

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

您的smallLists为空,因此您无法访问索引index。像这样改变它

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

请注意,您也可以在awaitAll()列表中调用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() }
}