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

Jetpack Compose中视图消失后ViewModel未被清除的原因排查

为什么你的ViewModel没有被清除?

你的MyViewModel未触发onCleared()的核心原因是ViewModel的作用域绑定逻辑不符合预期,具体细节如下:

1. 默认viewModel()的作用域是Activity/Fragment

在Compose中调用val viewModel: MyViewModel = viewModel()时,默认会将ViewModel的生命周期绑定到宿主ComponentActivity(也就是你的MainActivity),而非StateZero这个Composable的生命周期。

这意味着:

  • 只有当MainActivity被销毁时,ViewModel才会触发onCleared()
  • 即便StateZero因x的状态变化被从Composition中移除,ViewModel仍会保留在Activity的作用域内,不会被清除

2. 让ViewModel随Composable销毁而清除的方法

如果你希望ViewModel和StateZero的生命周期绑定,需要使用Compose专属的ViewModel作用域API,通过指定自定义的ViewModelStoreOwner实现:

修改StateZero的代码:

@Composable
fun StateZero() {
    // 创建与当前Composable绑定的ViewModel存储容器
    val viewModelStoreOwner = remember {
        object : ViewModelStoreOwner {
            private val store = ViewModelStore()
            override fun getViewModelStore(): ViewModelStore = store

            // 当Composable被移除时,清空存储容器,触发ViewModel的onCleared
            DisposableEffect(Unit) {
                onDispose {
                    store.clear()
                }
            }
        }
    }

    val viewModel: MyViewModel = viewModel(viewModelStoreOwner = viewModelStoreOwner)
    Text(text = "Should be clearing in a few seconds...")
}

或者使用更简洁的rememberViewModel(需依赖androidx.lifecycle:lifecycle-viewmodel-compose最新版本):

@Composable
fun StateZero() {
    val viewModel: MyViewModel = rememberViewModel()
    Text(text = "Should be clearing in a few seconds...")
}

rememberViewModel()会自动将ViewModel的生命周期绑定到当前Composable,当Composable从Composition中移除时,ViewModel会被清除并触发onCleared()。

3. 原代码的逻辑验证

你的代码中x的状态每隔1秒切换一次,StateZero和Text("NO")交替显示,但由于ViewModel绑定到Activity,每次StateZero重新进入Composition时,拿到的都是同一个ViewModel实例,且只有Activity销毁时才会触发onCleared()。

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 06:59:55