简体   繁体   English

全球小吃店处理 Jetpack Compose

[英]Global Snackbar Handling Jetpack Compose

Seeing as I have multiple places where snackbars could be triggered, I want to have a central place in my app where I can handle showing/dismissing snackbars.鉴于我有多个可以触发小吃店的地方,我想在我的应用程序中有一个中心位置,我可以在其中处理显示/关闭小吃店。

This is the structure of my app:这是我的应用程序的结构:

应用结构

I've implemented a BaseViewModel that contains a StateFlow which should keep track of the SnackBar message (every other ViewModel inherits from this BaseViewModel):我已经实现了一个包含 StateFlow 的 BaseViewModel,它应该跟踪 SnackBar 消息(所有其他 ViewModel 都继承自这个 BaseViewModel):

@HiltViewModel
open class BaseViewModel @Inject constructor() : ViewModel() {
    val _snackBarMessage = MutableStateFlow("")
    val snackBarMessage: StateFlow<String> = _snackBarMessage
}

To test if the update of the StateFlow is triggered correctly, I've implemented a message that should update the StateFlow after every login:为了测试 StateFlow 的更新是否被正确触发,我实现了一条消息,应该在每次登录后更新 StateFlow:

private fun setSnackBarMessage() {
   _snackBarMessage.value = "A wild snackBar appeared"
}

MainContent contains my Scaffold (incl. scaffoldState, snackbarHost), should react to changes in the snackBarMessage flow and display/dismiss the Snackbar when needed: MainContent 包含我的 Scaffold(包括scaffoldState、snackbarHost),应该对snackBarMessage 流中的变化做出反应,并在需要时显示/关闭 Snackbar:

fun MainContent(...){
   val message by viewModel.snackBarMessage.collectAsState()

   LaunchedEffect(message) {
      if (message.isNotEmpty() Timber.d("We got a snackbar")
   }

   Scaffold(...){...}
}

During debugging, I noticed that after every login the snackBarMessage value is updated correctly but MainContent does not get those updates which, in turn, means that the snackbar is never displayed.在调试过程中,我注意到每次登录后,snackBarMessage 值都会正确更新,但 MainContent 没有得到这些更新,这反过来意味着,snackbar 永远不会显示。

Is there a reason why MainContent does not get those updates from the LoginComposable? MainContent 没有从 LoginComposable 获取这些更新是否有原因? Is it even possible to have a central instance of a snackbar or do I really need to handle snackbars separately in every Composable?是否有可能有一个小吃店的中心实例,或者我真的需要在每个可组合中单独处理小吃店吗?

Probably, the cause of your problem is using message as the key for LaunchedEffect and not changing the message at the same time.可能您的问题的原因是使用消息作为LaunchedEffect的键,而不是同时更改消息。 In the documentation you can read that type of side-effect will be re-launched after key modification.在文档中,您可以阅读该类型的副作用将在密钥修改后重新启动。

If LaunchedEffect is recomposed with different keys (see the Restarting Effects section below), the existing coroutine will be cancelled and the new suspend function will be launched in a new coroutine.如果 LaunchedEffect 用不同的 key 重构(参见下面的 Restarting Effects 部分),现有的协程将被取消,新的挂起函数将在新的协程中启动。

Some effects in Compose, like LaunchedEffect, produceState, or DisposableEffect, take a variable number of arguments, keys, that are used to cancel the running effect and start a new one with the new keys. Compose 中的一些效果,如 LaunchedEffect、produceState 或 DisposableEffect,采用可变数量的参数和键,用于取消正在运行的效果并使用新键启动新效果。

I suggest wrapping snackbar message in some kind of object (not data class) with field containing snackbar content.我建议将小吃店消息包装在某种对象(不是数据类)中,其中包含包含小吃店内容的字段。

Cheers干杯

You can use this

@Composable
fun MainScreen() {
    val coroutineScope = rememberCoroutineScope()
    val showSnackBar: (
        message: String?,
        actionLabel: String,
        actionPerformed: () -> Unit,
        dismissed: () -> Unit
    ) -> Unit = { message, actionLabel, actionPerformed, dismissed ->
        coroutineScope.launch {
            val snackBarResult = scaffoldState.snackbarHostState.showSnackbar(
                message = message.toString(),
                actionLabel = actionLabel
            )
            when (snackBarResult) {
                SnackbarResult.ActionPerformed -> actionPerformed.invoke()
                SnackbarResult.Dismissed -> dismissed.invoke()
            }
        }
    }


    //Global using
    showSnackBar.invoke(
        "YOUR_MESSAGE",
        "ACTION_LABEL",
        {
         //TODO ON ACTION PERFORMED
        },
        {
         //TODO ON DISMISSED
        }
    )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM