如何在Jetpack Compose中处理一次性操作



注意-这个问题与这个问题几乎相同
如果有更好的方法,我正在寻找。

根据Android文档,

一旦显示了瞬态消息,UI需要通知的ViewModel,导致另一个UI状态更新:

例如,当我在单击按钮时显示Toast消息时,UI是否应该通知ViewModel Toast已成功显示
这是处理烤面包、小吃等一次性操作的最佳方法吗?

样本代码,

@Composable
fun OneShotOperation(
viewmodel: OneShotOperationViewModel = viewModel(),
) {
val context = LocalContext.current
LaunchedEffect(
key1 = viewmodel.toastMessage,
) {
if (viewmodel.toastMessage.isNotBlank()) {
Toast.makeText(
context,
viewmodel.toastMessage,
Toast.LENGTH_SHORT,
).show()
viewmodel.toastMessage = "" // Is this the correct way?
}
}
Button(
onClick = {
viewmodel.toastMessage = "Sample Toast"
},
) {
Text(text = "Show Toast")
}
}
class OneShotOperationViewModel : ViewModel() {
var toastMessage by mutableStateOf(
value = "",
)
}

如果我删除这一行,
viewmodel.toastMessage = "" // Is this the correct way?
toast只显示一次,后续按下的按钮不会显示toast,因为可变状态没有改变。

对于这样的工作,我更喜欢使用SharedFlow

请注意,如果在collect未运行时从另一个视图发送消息,则在您最终启动它时,它不会显示toast。它不存储值,只将其传递给当前连接的所有收集器。

class OneShotOperationViewModel : ViewModel() {
private val _toastMessage = MutableSharedFlow<String>()
val toastMessage = _toastMessage.asSharedFlow()
fun sendMessage(message: String) {
viewModelScope.launch {
_toastMessage.emit(message)
}
}
}
@Composable
fun TestScreen() {
val context = LocalContext.current
val viewModel = viewModel<OneShotOperationViewModel>()
LaunchedEffect(Unit) {
viewModel
.toastMessage
.collect { message ->
Toast.makeText(
context,
message,
Toast.LENGTH_SHORT,
).show()
}
}
Button(
onClick = {
viewModel.sendMessage("Sample Toast")
},
) {
Text(text = "Show Toast")
}
}

而不是使用

viewmodel.toastMessage = "" // Is this the correct way?

您可以将消息包装成一个简单的包装器:

class ToastMessageWrapper(val value: String)

并在mutableStateOf():中使用此类

val toastMessage: ToastMessageWrapper by mutableStateOf(null)

然后LaunchedEffect将根据每个新值进行更新。请注意,我使用的是class,而不是data class。因为即使对于相同的值,我们每次都必须保持这些类的不同。

最新更新