视图模型:
class RulesViewModel : ViewModel() {
private val _sharedFlow = MutableSharedFlow<ScreenEvents>()
val sharedFlow = _sharedFlow.asSharedFlow()
sealed class ScreenEvents {
data class ShowSnackbar(val message: String) : ScreenEvents()
data class Navigate(val route: String) : ScreenEvents()
}
}
可组合:
@Composable
fun EventListener(
rulesVm: RulesViewModel,
) {
LaunchedEffect(key1 = true) {
rulesVm.sharedFlow.collect { event ->
when(event) {
is RulesViewModel.ScreenEvents.ShowSnackbar -> {
SnackbarScreen("snackbar ${event.message}")
}
is RulesViewModel.ScreenEvents.Navigate -> {
// todo
}
}
}
}
}
这给出了一条错误消息:@Composable 调用只能在 @Composable 函数的上下文中发生
从 viewModel 收集流并在可组合项中对它们进行操作的最佳实践是什么?
最好使用扩展 - Flow。collectAsState()
您的情况是:
val screenState = rulesVm.sharedFlow.collectAsState
然后在可组合函数的主体中,您可以:
@Composable
fun EventListener(
rulesVm: RulesViewModel,
) {
val screenState = rulesVm.sharedFlow.collectAsState()
when(screenState) {
is RulesViewModel.ScreenEvents.ShowSnackbar -> {
SnackbarScreen("snackbar ${event.message}")
}
is RulesViewModel.ScreenEvents.Navigate -> {
// todo
}
}
}
您无法在 LaunchedEffect 主体和 Flow.collect() 内部调用可组合函数,因为它是协程作用域的扩展,而不是可组合函数。
我认为您希望看到以下行为:您调度一个事件,并且小吃栏出现在当前屏幕上,而无需转到另一个屏幕。如果您在接收事件时不需要考虑应用程序生命周期,那么下面的示例将适合您。我创建了一个scaffoldState,用它来显示Snaskbar。由于 Unit 是一个对象,因此订阅发生一次。
val scaffoldState = rememberScaffoldState()
LaunchedEffect(Unit) {
rulesVm.sharedFlow.collect { event ->
when(event) {
is RulesViewModel.ScreenEvents.Navigate -> TODO("Add navigation to another screen")
is RulesViewModel.ScreenEvents.ShowSnackbar ->
scaffoldState.snackbarHostState.showSnackbar(
message = "snackbar ${event.message}"
)
}
}
}
Scaffold(
scaffoldState = scaffoldState,
snackbarHost = { snackbarHostState ->
SnackbarHost(snackbarHostState) { data ->
Snackbar(
snackbarData = data
)
}
}
) {
TODO("Add your screen content")
}