最近我发现了一个我无法理解的流行为。
问题描述
考虑这种情况:
你有一个父 flow
并且在它的 collect
中,你将有一个“子”flow
并调用 .collect()
,像这样:
parentFlow.collect {
childFlow.collect()
}
然后,如果 parentFlow 发出一些值,则不会调用 childFlow.collect()
。
我尝试过的
通过在 SO 上进行一些搜索,我发现以下问题与我的类似:
- Android: collecting a Kotlin Flow inside another not emitting
- Chaining Flows (collecting a Flow within the collect{} block of another Flow)
但是我打算更深入地挖掘这种行为背后的原因,因此我创建了一个项目来可靠地重现它,您可以在 github 上查看它: https://github.com/dumbfingers/Playground/tree/flow-inside-flow
在这个迷你重现中,我放了一些日志输出。当你点击按钮时,预期的日志输出应该是:
Test: onArrayUpdated
Test: item: {some number}
Test: item: {some number}
Test: onFlowChanged
Test: repoObserve delayed
Test: item: {some number}
Test: item: {some number}
Test: repoAnotherObserve delayed
然而,实际结果是:
Test: onArrayUpdated
Test: item: {some number}
Test: item: {some number}
这表明 randomFlow
中的这两个 collect
调用没有被调用:
repository.repoObserve(list).collect {
repository.repoAnotherObserve().collect()
}
问题
在这个 SO 中:Android: collecting a Kotlin Flow inside another not emitting 答案表明“收集无限流量”导致了这个问题。
在我的实验中,要么
- 将
repoObserve
和repoAnotherObserve
更改为suspend
方法并使它们不返回流
或
- 使用
combine
组合这些流
将解决这个问题。
但为什么另一个流的收集中的收集流不起作用?
最佳答案
您可以在父 collect { ... } block 中启动协程
val scope: CoroutineScope = ...
parentFlow.collect {
scope.launch {
childFlow.collect()
}
}
或
parentFlow.flatMapMerge { childFlow }.collect {
// logic here ...
}
您还可以将 flatMapMerge
替换为 flatMapLatest
/flatMapConcat
/flatMapFirst
(FlowExt 图书馆)
希望能帮到你
关于android - Kotlin flow inside flow,父流不调用collect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71615847/