问题描述
我最近开始研究一个使用kotlin flow + coroutine的项目,发现了一个奇怪的东西,我编写了一些代码来重现问题,这是代码
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.channels.*
sealed class ViewIntent {
class Initial : ViewIntent()
class Refresh : ViewIntent()
class Click: ViewIntent()
}
class ViewState
@kotlinx.coroutines.ExperimentalCoroutinesApi
fun Flow<ViewIntent>.toEvent() : Flow<Int> {
return merge(
filterisinstance<ViewIntent.Initial>().map{1},filterisinstance<ViewIntent.Refresh>().map{2},filterisinstance<ViewIntent.Click>().map{3},)
}
@kotlinx.coroutines.ExperimentalCoroutinesApi
fun main() = runBlocking {
val intentFlow = listof(ViewIntent.Initial()).asFlow()
intentFlow.onEach { println(it) }
.toEvent()
.collect()
}
ViewIntent$Initial@2ff5659e
ViewIntent$Initial@2ff5659e
ViewIntent$Initial@2ff5659e
让我感到困惑的是为什么为什么ViewIntent $ Initial @ 2ff5659e被显示3次?如果删除.toEvent(),则仅显示一个ViewIntent $ Initial @ 2ff5659e。
解决方法
因为Flow
是冷流。每次您呼叫filterIsInstance
时,上游都会发出ViewIntent.Initial()
。
将来,SharedFlow
将被添加到库中,请参见pull request,我们可以这样写:
@kotlinx.coroutines.ExperimentalCoroutinesApi
fun Flow<ViewIntent>.toEvent(coroutineScope: CoroutineScope) : Flow<Int> {
val shared = this.shareIn(
coroutineScope,replay = 0,started = SharingStarted.WhileSubscribed()
)
return merge(
shared.filterIsInstance<ViewIntent.Initial>().map{1},shared.filterIsInstance<ViewIntent.Refresh>().map{2},shared.filterIsInstance<ViewIntent.Click>().map{3},)
}