[英]Collect flow but only any new values, not the currently existing value
目前正在努力解决这个问题,到目前为止,SharedFlow 和 StateFlow 的组合都没有奏效。
我有一个可能已经从一个值开始的流程,或者不是。
使用该流程,我想收集开始收集后发出的任何新值。
此刻我所有的尝试总是失败,无论我尝试什么,它总是在我开始收集时立即获得当前值。
我试图实现的一个例子:
我希望能够做到以下几点:
尝试了 SharedFlow 和 Stateflow,尝试了 replay = 0 和 WhileSubscribed,我找不到任何组合可以满足我的要求。
到目前为止,我发现的唯一解决方法是在本地注册我启动 my.collect{ } 的时间,并与我在收集中收到的项目的开始时间进行比较。 在这种情况下,我使用的 object 具有特定的起始时间,但这种解决方法不适用于上述整数示例。
编辑:根据 SharedFlow 的要求添加实现示例
这与返回 Flow<MyObject> 的 Room 数据库调用相关联
我的片段.kt
lifecycleScope.launch(Dispatchers.IO) {
viewModel.getMyObjectFlow.shareIn(
viewModel.viewModelScope, // also tried with fragment lifecyclescope
SharingStarted.WhileSubscribed(), // also tried with the other 2 options
replay = 0,
).collect{
...
}
}
在这样的使用站点上使用shareIn
是没有意义的。 您正在创建一个无法共享的共享流,因为您没有存储其他类访问和使用的引用。
无论如何,问题是您正在使用站点创建 SharedFlow,因此您的共享流仅在片段调用此代码时才开始从上游收集。 如果上游流很冷,那么您将获得冷流发出的第一个值。
SharedFlow 应该在 ViewModel 中创建并放入一个属性中,以便每个 Fragment 都可以从同一个实例中收集。 您将需要使用 SharingStarted.Eagerly 来防止冷上游流在休息后有新订阅者时从头开始重新启动。
您对流程的工作方式有误解。 它们总是仅在您开始收集后才会发出。 他们按需发射。 让我们来看看这个例子:
val flow1 = flow {
println("Emitting 1")
emit(1)
delay(10.seconds)
println("Emitting 2")
emit(2)
}
delay(5.seconds)
println("Start collecting")
flow1.collect {
println("Collected: $it")
}
output 是:
Start collecting
Emitting 1
Collected: 1
不是:
Emitting 1
Start collecting
Collected: 1
这是因为流仅在您开始收集它之后才开始发射。 否则,它将无处发射。
当然,有些流是从某种缓存、队列或缓冲区发出的。 例如,共享流就是这样做的。 在这种情况下,它看起来像您在发射后收集。 但事实并非如此。 从技术上讲,它的工作原理是这样的:
val buffer = listOf(1 , 2, 3)
val flow1 = flow {
buffer.forEach {
println("Emitting $it")
emit(it)
}
}
在您开始收集后它仍然会发出,但它只是从缓存中发出。 当然,在您开始收集之前,该项目已添加到缓存中,但这完全是从您那里抽象出来的。 您不知道为什么流程会发出一个项目。 从收集器的角度来看,它总是刚刚发出,而不是过去。 同样,您无法知道网络服务器是从数据库还是从缓存中读取数据——这是从您那里抽象出来的。
总结:不可能以通用方式仅从任何流中收集新项目。 流程一般不理解“新项目”的概念。 他们只是发射,但你不知道他们为什么这样做。 也许他们以某种方式即时生成项目,也许他们被动地观察外部事件,或者他们重新传输他们从另一个流程收集的一些项目。 你不知道。
在开发解决方案时,您需要了解项目的来源并相应地开发代码。 例如,如果源是常规冷流,则在您开始收集之前它永远不会开始做任何事情。 如果源是 state 流,您可以只删除第一项。 如果是共享流或者带有一些重放缓冲区的流,那么情况就更复杂了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.