【问题标题】:How to handle one-shot operations in Jetpack Compose?如何在 Jetpack Compose 中处理一次性操作?
【发布时间】:2022-02-08 23:21:15
【问题描述】:

注意 - 这个问题和this one差不多。
如果有的话,我正在寻找更好的方法。

根据Android Docs

一旦显示瞬态消息,用户界面需要通知 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,因为可变状态没有改变。

【问题讨论】:

  • 如果您删除 viewmodel.toastMessage = "" 您将无法再次显示相同的消息。而不是修改视图模型的属性,它应该调用适当的方法,你需要在你的视图模型中使用 fun toastShown() {toastMessage = ""} 之类的东西。

标签: android android-jetpack-compose


【解决方案1】:

这些问题没有灵丹妙药,这完全取决于您的情况。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2023-01-20
    • 2021-10-27
    • 2022-10-23
    • 2023-02-04
    • 2023-01-13
    • 2022-10-09
    相关资源
    最近更新 更多