这里有一个代码示例
// Viewmodel
sealed interface Event {
object A : Event
object B : Event
}
private val _event = Channel<Event>(Channel.UNLIMITED)
val event = _event.receiveAsFlow()
sealed interface Intent {
class A : Intent
class B : Intent
}
fun sendIntent(intent: Intent) {
when (intent) {
is Intent.A -> viewModelScope.launch { _event.send(Event.A) }
is Intent.B -> viewModelScope.launch { _event.send(Event.B) }
}
}
// Compose UI
@Composable
fun UI(){
val vm = koinViewModel<TestVM.VM>()
val event = remember { vm.event }
Element1(event)
LaunchedEffect(Unit){
event.filterIsInstance<Event.A>().collect{
// ловим А
}
}
}
@Composable
fun Element1(
event : Flow<Event>
){
LaunchedEffect(Unit){
event.filterIsInstance<Event.B>().collect{
// ловим B
}
}
}
本质上我们有两种类型的事件。
Event.A
不以任何方式依赖于 UI。处理其事件是转换到另一个屏幕,显示 Toast 和其他类似事件。它可以很容易地放置在根函数中UI()
但这Event.B
是一个取决于 UI 的事件。例如:用红色突出显示某些文本2秒,然后返回正常颜色。或将列表滚动到特定位置。
它应该是可以影响文本颜色或引用的地方ListState
。必须在某些函数内。
此类代码的问题在于,如果我们有一个事件侦听器来过滤它们filterIsInstance
,那么它会捕获它们,无论filterIsInstance
i.e.该事件被视为已在过滤阶段收集。并且没有考虑它没有通过过滤器的事实。
我看到了一种出路,但我不喜欢它:
放弃sealed Event
相同的方法Channel<Event>
并为每个事件创建自己的方法Channel<DataType>
告诉我在这种情况下该怎么办。
作为一种选择,检查过滤器之后是否有事件,而不是
collect
空事件上的调用流。示例代码:我为我的问题找到了这个解决方案:
这就是我们得到的: