Jetpack Compose 从视图模型展示小吃吧 - 单个现场活动

Bak*_*Bak 5 events android kotlin android-viewmodel android-jetpack-compose

我正在构建一个 jetpack compose 应用程序,我希望我的视图模型告诉我的 compose 函数通过向它发送一个事件来显示一个小吃店。我已经阅读了多篇关于 Kotlin 单一实时事件案例的博客文章,我尝试使用 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"))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
@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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Bak*_*Bak 5

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

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

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

    private fun showSnackBar() {
        isSnackBarShowing = true
    }

    fun dismissSnackBar() {
        isSnackBarShowing = false
    }
}
Run Code Online (Sandbox Code Playgroud)

在视图中,您使用 LaunchedEffect 来检查在重新组合视图时是否应该显示小吃栏

@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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)