我是 jetpack compose 的新手,每当我观察到的错误消息不为空时,我都会尝试显示错误信息栏。
Scaffold(scaffoldState = scaffoldState) {
LaunchedEffect(errorMessage) {
if (errorMessage != null) {
scope.launch {
scaffoldState.snackbarHostState.showSnackbar(errorMessage)
}
}
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
//some ui components inside here
}
}
上述代码中的问题是,第一次错误消息从 null 更改为特定消息时,它看起来很好。但是,如果重复的用户操作产生相同的错误消息,则不会再次出现。
P.S - 我知道发生这种情况是因为将
errorMessage
作为键放在 LaunchedEffect
内。我的疑问是,是否有不同的方法来实现我想要的?
发生这种情况是因为
LaunchedEffect
将再次运行,以防万一 errorMessage
发生变化。
你能做的是:
LaunchedEffect(errorMessage) {
if (errorMessage != null) {
resetErrorMessage() // reset errorMessage
scope.launch {
scaffoldState.snackbarHostState.showSnackbar(errorMessage)
}
}
}
resetErrorMessage
必须将errorMessage
设置为空,因此LaunchedEffect
将再次运行,但由于您正在检查它是否不为空,因此不会发生任何事情。但一旦收到新的错误消息,LaunchedEffect
就会再次执行。
我发现上面提供的答案存在一些问题
首先,不需要在
LaunchedEffect
中重新启动协程(它也会执行挂起函数),因此我们可以从 scope.launch
中删除
LaunchedEffect
其次,如果我们在
resetErrorMessage()
发生之前使用 .showSnackBar
,我们将发出一条 null(空)消息。我们应该在执行showSnackbar
后重置错误消息。
LaunchedEffect(errorMessage) {
if (errorMessage != null) {
scaffoldState.snackbarHostState.showSnackbar(errorMessage)
resetErrorMessage() // reset errorMessage
}
}
我的解决方案是支持重复的消息/错误,并且不要多次显示一条消息/错误。重组将被称为只是
1.创建一个智能委托,在读取后删除该值。这是主要逻辑
class OnceReadDelegate<T>(private var value: T? = null) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val currentValue = value
value = null
return currentValue
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
value = newValue
}
}
2.创建一个 Message 类来管理我们的文本和消息类型
class Message {
var payload by OnceReadDelegate<String?>()
var type: MessageType = MessageType.Error
companion object {
fun create(text: String?, messageType: MessageType = MessageType.Error) =
Message().apply {
payload = text
this.type = messageType
}
}
}
sealed class MessageType {
data object Regular : MessageType()
data object Error : MessageType()
}
3.我的状态类与消息类的示例
data class SettingsPageState(
val listWidgetState: List<WidgetViewState> = emptyList(),
val listAgeFormat: List<AgeFormat> = emptyList(),
val message: Message? = null,
val isLoading: Boolean = true,
val isEmpty: Boolean = false
)
4.我用新消息更新状态的示例
mutableState.update { previousState ->
previousState.copy(message = Message.create(exception?.message))
}
5.最后Composable函数如何如何Snackbar
@Composable
fun SettingsScreen() {
...
LaunchedEffect(state.message) {
val text = state.message?.payload
if (!text.isNullOrEmpty()) {
//your method to show snackbar
onShowSnackbar(text , null)
}
}
...
}
就是全部)