kotlin 无法从Flow获取以前发出的值

zrfyljdw  于 2023-02-13  发布在  Kotlin
关注(0)|答案(2)|浏览(257)

无法从Flow获取以前发出的值。

class TestActivity: ComponentActivity() {
...

private val flowA = MutableStateFlow(0)

private val flowB = MutableStateFlow("")

init {
    flowB.onEach { Log.d("flowtest", "test - $it") }
        .launchIn(lifecycleScope)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    flowB.value = "1"
    flowB.value = "2"
    flowB.value = "3"

    flowA.map { "ignore" }
        .onEach {
            flowB.value = "4"
            flowB.value = "5"
            flowB.value = "6"
        }
        .launchIn(lifecycleScope)

    flowA.value = 0
    
...
}

期待
试验-1
试验-2
试验-3
试验-4
试验-5
测试-6
结果
试验-1
试验-2
试验-3
测试-6
"心流"的概念有什么缺失?
如何获取以前的发射值?

ufj5ltwl

ufj5ltwl1#

这只是一个猜测,因为我并不想费心去做一个项目并测试它。
首先,关于StateFlow有两件事需要记住。
1.它被限制为历史记录1。它只能向新订阅者重播单个值。
1.它是合并的,这意味着如果收集器的速度慢于输入的排放量,收集器将错过一些排放值,而只得到最新的值。
因此,查看您的代码,乍一看,您可能只会看到:

test - 3
test - 6

这是因为您是在主线程上发射,并在主线程上收集,所以无论何时您在一行中有多个StateFlow值更改,我希望只有在方法中调用的最后一个值“保留”,因为收集器必须等待轮到它的主线程被放弃,然后才能收集它的下一个值。
那么,为什么会出现12呢?
实际上,lifecycleScope并没有使用Dispatchers.Main,它使用Dispatchers.Main.immediateDispatchers.Main.immediate的行为稍有不同。如果你已经在Main线程上,immediate版本会立即运行挂起的代码,而不是先让位给其他协程。
所以,我的理论是,当你在主线程上更改值时,但是你在Dispatchers.Main.immediate上收集flowBonEach,所以每当你向flowB发出一个值时,它就有机会立即运行它的onEach
但是,提醒一下,我实际上还没有用immediate测试流来检验这个假设,这只是我能想到的唯一解释这个行为的原因。要自己检验这个理论,你可以在两个地方都使用launchIn(lifecycleScope + Dispatchers.Main),看看12是否消失了。

k5ifujac

k5ifujac2#

实际上,这段代码有问题,因为value属性是stateFlow属性,而不是sharedFlow属性。另外,如果收集器和订阅器在同一个协程中,则无法在收集数据后向stateFlow添加值。因此,正确的代码应为:

val flowA = MutableSharedFlow<Int>()

val flowB = MutableStateFlow("")

flowA.map { "test $it" }
    .onEach { flowB.value = it }

flowB.value = "1"
flowB.value = "2"
flowB.value = "3"

flowB.collect { println(it) }

结果将是:3
因为***stateFlow只保留最后发出的一个***
如果你想得到所有的值,你可以像这样使用SharedFlow:

suspend fun main():Unit = coroutineScope {

val flowA = MutableSharedFlow<Int>()

launch {
    flowA.collect {
        println(it)
    }
}

launch {
    flowA.emit(1)
    flowA.emit(2)
    flowA.emit(3)
}

您可以查看文档以获取更多信息SharedFlowStateFlow

相关问题