You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在非Compose函数中用strings.xml设置Snackbar的消息与操作文本?

解决方案

方法1:传递资源ID到UI层解析(推荐)

ViewModel的职责是处理业务逻辑,不应该直接依赖Context做字符串解析。正确的做法是把strings.xml对应的资源ID传给UiEvent,在Compose界面中拿到Context后再转换为实际字符串。

  1. 修改UiEvent定义,改为接收资源ID:
sealed class UiEvent {
    data class ShowSnackbar(
        val messageResId: Int,
        val actionResId: Int? = null
    ) : UiEvent()
}
  1. 在ViewModel的onEvent方法中传递资源ID:
fun onEvent(event: TaskListEvent) {
    when (event) {
        is TaskListEvent.OnDeleteTask -> {
            viewModelScope.launch(Dispatchers.IO) {
                deletedTask = event.task
                repository.deleteTask(event.task)
                sendUiEvent(
                    UiEvent.ShowSnackbar(
                        messageResId = R.string.task_deleted_success,
                        actionResId = R.string.undo
                    )
                )
            }
        }
        // 其他事件处理逻辑
    }
}
  1. 在Compose界面中处理UiEvent时,用LocalContext解析字符串:
val context = LocalContext.current
LaunchedEffect(uiEvent) {
    uiEvent.collect { event ->
        when (event) {
            is UiEvent.ShowSnackbar -> {
                // 以Compose的SnackbarHost为例
                SnackbarHostState.current.showSnackbar(
                    message = context.getString(event.messageResId),
                    actionLabel = event.actionResId?.let { context.getString(it) },
                    duration = SnackbarDuration.Long
                ).apply {
                    if (this == SnackbarResult.ActionPerformed) {
                        // 执行撤销操作的逻辑
                    }
                }
            }
        }
    }
}

方法2:在ViewModel中注入Application Context(不推荐)

如果必须在ViewModel内完成字符串解析,可以通过构造函数注入Application(只能用Application Context,避免内存泄漏):

  1. 修改ViewModel构造函数:
class TaskViewModel(
    private val repository: TaskRepository,
    application: Application
) : ViewModel() {
    private val appContext = application.applicationContext

    fun onEvent(event: TaskListEvent) {
        when (event) {
            is TaskListEvent.OnDeleteTask -> {
                viewModelScope.launch(Dispatchers.IO) {
                    deletedTask = event.task
                    repository.deleteTask(event.task)
                    sendUiEvent(
                        UiEvent.ShowSnackbar(
                            message = appContext.getString(R.string.task_deleted_success),
                            action = appContext.getString(R.string.undo)
                        )
                    )
                }
            }
        }
    }
}
  1. 创建ViewModel时传入Application:
val viewModel = ViewModelProvider(
    this,
    TaskViewModelFactory(repository, application)
)[TaskViewModel::class.java]

关键提醒

  • 优先选择方法1,符合MVVM架构的职责分离原则,避免ViewModel依赖Context带来的潜在内存泄漏风险。
  • 若使用方法2,必须严格使用Application的Context,绝对不能传入Activity/Fragment的Context。

内容的提问来源于stack exchange,提问作者Juncu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:35:20