繁体   English   中英

收集流,但只收集任何新值,而不是当前存在的值

[英]Collect flow but only any new values, not the currently existing value

目前正在努力解决这个问题,到目前为止,SharedFlow 和 StateFlow 的组合都没有奏效。

我有一个可能已经从一个值开始的流程,或者不是。

使用该流程,我想收集开始收集后发出的任何值。

此刻我所有的尝试总是失败,无论我尝试什么,它总是在我开始收集时立即获得当前值。

我试图实现的一个例子:

  • 给定具有以下时间线的 Flow(可以是任何类型,Int 只是为了简化):发出值 4 | 发出值 2 | 发出值 10

我希望能够做到以下几点:

  • 如果我在值 4 已经发出后开始收集,我只想在那之后接收任何东西,在这种情况下,它会在发出后收集 2 和 10
  • 如果我在值 2 之后开始收集,那么它只会收到 10
  • 如果我在 4 点之前开始收集,那么它将收到 4、2 和 10

尝试了 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM