Compose Snackbar 不会出现重复错误

问题描述 投票:0回答:3

我是 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
内。我的疑问是,是否有不同的方法来实现我想要的?

android kotlin android-jetpack-compose android-snackbar
3个回答
6
投票

发生这种情况是因为

LaunchedEffect
将再次运行,以防万一
errorMessage
发生变化。 你能做的是:

LaunchedEffect(errorMessage) {
   if (errorMessage != null) {
        resetErrorMessage() // reset errorMessage
        scope.launch {
            scaffoldState.snackbarHostState.showSnackbar(errorMessage)
        }
   }
}

resetErrorMessage
必须将
errorMessage
设置为空,因此
LaunchedEffect
将再次运行,但由于您正在检查它是否不为空,因此不会发生任何事情。但一旦收到新的错误消息,
LaunchedEffect
就会再次执行。


1
投票

我发现上面提供的答案存在一些问题

首先,不需要在

LaunchedEffect
中重新启动协程(它也会执行挂起函数),因此我们可以从
scope.launch
 中删除 
LaunchedEffect

其次,如果我们在

resetErrorMessage()
发生之前使用
.showSnackBar
,我们将发出一条 null(空)消息。我们应该在执行
showSnackbar
后重置错误消息。

LaunchedEffect(errorMessage) {
   if (errorMessage != null) {
        scaffoldState.snackbarHostState.showSnackbar(errorMessage)
        resetErrorMessage() // reset errorMessage
   }
}

0
投票

我的解决方案是支持重复的消息/错误,并且不要多次显示一条消息/错误。重组将被称为只是

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

就是全部)

© www.soinside.com 2019 - 2024. All rights reserved.