问题描述
我想知道是否有一种干净的方法可以在 Kotlin 中启动一系列流,然后在解决它们之后,根据它们是否成功执行进一步的操作
例如,我需要从数据库中读取所有整数(将它们返回到流中),检查它们是否针对外部 API 是偶数还是奇数(也返回流),然后从数据库中删除奇数
在代码中它会是这样的
fun findEven() {
db.readIntegers()
.map { listofInt ->
listofInt.asFlow()
.flatMapMerge { singleInt ->
httpClient.apiCalltocheckForOddity(singleInt)
.catch {
// API failure when number is even
}
.map {
// API success when number is odd
db.remove(singleInt).collect()
}
}.collect()
}.collect()
}
但我在这段代码中看到的问题是访问并行完成的 DB 删除条目,我认为更好的解决方案是运行所有 API 调用并在某处收集所有失败和成功的内容,所以要只能在数据库中进行一次批量插入,而不是让多个协程自己做
解决方法
在我看来,在 map
、filter
等中产生副作用是一种反模式。像从数据库中删除项目这样的副作用应该是一个单独的步骤({{ 1}} 在 Flow 的情况下,而 collect
在 List 的情况下)为清楚起见。
嵌套流也有点复杂,因为您可以直接将列表修改为 List。
我认为您可以这样做,假设 API 一次只能检查一项。
forEach
并行版本,如果 API 调用返回参数。 (By the way,Kotlin APIs should not throw exceptions on non-programmer errors)。
suspend fun findEven() {
db.readIntegers()
.map { listOfInt ->
listOfInt.filter { singleInt ->
runCatching {
httpClient.apiCallToCheckForOddity(singleInt)
}.isSuccess
}
}
.collect { listOfOddInt ->
db.removeAll(listOfOddInt)
}
}