繁体   English   中英

全球小吃店处理 Jetpack Compose

[英]Global Snackbar Handling Jetpack Compose

鉴于我有多个可以触发小吃店的地方,我想在我的应用程序中有一个中心位置,我可以在其中处理显示/关闭小吃店。

这是我的应用程序的结构:

应用结构

我已经实现了一个包含 StateFlow 的 BaseViewModel,它应该跟踪 SnackBar 消息(所有其他 ViewModel 都继承自这个 BaseViewModel):

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

为了测试 StateFlow 的更新是否被正确触发,我实现了一条消息,应该在每次登录后更新 StateFlow:

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

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(...){...}
}

在调试过程中,我注意到每次登录后,snackBarMessage 值都会正确更新,但 MainContent 没有得到这些更新,这反过来意味着,snackbar 永远不会显示。

MainContent 没有从 LoginComposable 获取这些更新是否有原因? 是否有可能有一个小吃店的中心实例,或者我真的需要在每个可组合中单独处理小吃店吗?

可能您的问题的原因是使用消息作为LaunchedEffect的键,而不是同时更改消息。 在文档中,您可以阅读该类型的副作用将在密钥修改后重新启动。

如果 LaunchedEffect 用不同的 key 重构(参见下面的 Restarting Effects 部分),现有的协程将被取消,新的挂起函数将在新的协程中启动。

Compose 中的一些效果,如 LaunchedEffect、produceState 或 DisposableEffect,采用可变数量的参数和键,用于取消正在运行的效果并使用新键启动新效果。

我建议将小吃店消息包装在某种对象(不是数据类)中,其中包含包含小吃店内容的字段。

干杯

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