我遇到一种情况,我需要调度仅在运行时才知道的不确定数量的网络调用。每个呼叫都会返回一个列表。返回每个列表时,我需要将这些列表合并到一个合并的列表中。我正在使用协程执行此操作。
我遇到的问题与以下事实有关:我不知道该应用程序需要进行多少次网络通话。为了解决这个问题,我使用循环在运行时遍历调用列表:
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()
}
这里可能是一个简单的解决方案,但我看不到。任何帮助表示赞赏。
答案 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() }
}