Jetpack Compose 显示视图模型中的小吃栏 - 单个现场活动

Jetpack Compose show snack bar from view model - Single Live Event

我正在构建一个 Jetpack Compose 应用程序,我希望我的视图模型告诉我的 Compose 函数通过向它发送一个事件来显示小吃店。我已经阅读了多篇关于使用 Kotlin 的 Single Live Event 案例的博客文章,并且我尝试使用 Compose 和 Kotlin Flow 来实现它。我设法从视图模型发送事件(我在日志中看到它)但我不知道如何在可组合函数中接收它。有人可以帮我弄清楚吗?这是我的实现。

class HomeViewModel() : ViewModel() {
    sealed class Event {
        object ShowSheet : Event()
        object HideSheet : Event()
        data class ShowSnackBar(val text: String) : Event()
    }

    private val eventChannel = Channel<Event>(Channel.BUFFERED)
    val eventsFlow: Flow<Event> = eventChannel.receiveAsFlow()

    fun showSnackbar() {
        Timber.d("Show snackbar button pressed")
        viewModelScope.launch {
            eventChannel.send(Event.ShowSnackBar("SnackBar"))
        }
    }
}
@Composable
fun HomeScreen(
    viewModel: HomeViewModel,
) {
    val context = LocalContext.current

    val scaffoldState = rememberScaffoldState()
    val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)

    val lifecycleOwner = LocalLifecycleOwner.current
    val eventsFlowLifecycleAware = remember(viewModel.eventsFlow, lifecycleOwner) {
        eventsFlow.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
    }

    LaunchedEffect(sheetState, scaffoldState.snackbarHostState) {
        eventsFlowLifecycleAware.onEach {
            when (it) {
                HomeViewModel.Event.ShowSheet -> {
                    Timber.d("Show sheet event received")
                    sheetState.show()
                }
                HomeViewModel.Event.HideSheet -> {
                    Timber.d("Hide sheet event received")
                    sheetState.hide()
                }
                is HomeViewModel.Event.ShowSnackBar -> {
                    Timber.d("Show snack bar received")
                    scaffoldState.snackbarHostState.showSnackbar(
                        context.getString(it.resId)
                    )
                }
            }
        }
    }

    ModalBottomSheetLayout(
        sheetState = sheetState,
        sheetContent = {
            Text("Sheet")
        }
    ) {
        Button(
            onClick = {
                viewModel.showSheet()
            }
        ) {
            Text("Show SnackBar")
        }
    }
}

作为参考,我使用了这些博文:

我认为您必须收集 eventsFlowLifecycleAware 作为 state 才能正确触发可组合项。

尝试删除 LaunchedEffect 块,然后像这样使用它:

val event by eventsFlowLifecycleAware.collectAsState(null)
when (event) {
    is HomeViewModel.Event.ShowSnackBar -> {
        // Do stuff
    }
}

好的,我使用了错误的方法,我不能发送事件,我必须更新视图状态并检查我是否应该在重组时显示小吃栏。类似的东西:

您将 SnackBar 状态存储在视图模型中

class HomeViewModel: ViewModel() {
    var isSnackBarShowing: Boolean by mutableStateOf(false)
        private set

    private fun showSnackBar() {
        isSnackBarShowing = true
    }

    fun dismissSnackBar() {
        isSnackBarShowing = false
    }
}

并且在视图中,您使用 LaunchedEffect 来检查在重构视图时是否应该显示 snackbar

@Composable
fun HomeScreen(
    viewModel: HomeViewModel,
) {
    val onDismissSnackBarState by rememberUpdatedState(newValue = onDismissSnackBar)

    if (isSnackBarShowing) {
        val snackBarMessage = "Message"
        LaunchedEffect(isSnackBarShowing) {
            try {
                when (scaffoldState.snackbarHostState.showSnackbar(
                    snackBarMessage,
                )) {
                    SnackbarResult.Dismissed -> {
                    }
                }
            } finally {
                onDismissSnackBarState()
            }
        }
    }

    Row() {
        Text(text = "Hello")
        Spacer(modifier = Modifier.weight(1f))
        Button(
            onClick = {
                viewModel.showSnackBar()
            }
        ) {
            Text(text = "Show SnackBar")
        }
    }
}