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

配置变更(屏幕旋转)时ViewModel重建问题:带Factory实例如何持久化?

Jetpack Compose ViewModel配置变更持久化问题解析

为什么第一种写法能保持ViewModel持久化?

viewModel()是Compose封装的便捷函数,它会自动关联当前Activity/Fragment级别的ViewModelStoreOwner——这个Owner的生命周期在屏幕旋转等配置变更时不会被销毁,对应的ViewModelStore会被系统保留。同时函数默认以ViewModel的类名作为唯一标识key,配置变更后,函数会直接从已有的ViewModelStore中取出实例,不会重新创建。

第二种写法失效的原因

你的代码存在两个核心问题:

  1. 代码位置错误:LocalViewModelStoreOwner.current是Compose专属的CompositionLocal,只能在可组合函数内部访问,不能直接放在Activity的onCreate方法里。强行在onCreate中调用会获取不到正确的Owner,导致ViewModel无法绑定到能跨配置变更保留的ViewModelStore上。
  2. Factory语法错误:ExampleViewModelFactory的create方法里,参数Class<t>是小写的泛型参数,正确写法应该是Class<T>,这属于语法错误(大概率是你输入时的笔误,但会导致编译异常)。

正确实现带参数ViewModel的持久化

方式一:在Composable函数中直接使用

在可组合函数内部调用viewModel函数,无需手动指定Owner(默认绑定顶层Activity/Fragment级别的Owner),只需传入Factory即可:

@Composable
fun ExampleScreen() {
    val application = LocalContext.current.applicationContext as Application
    // 自动绑定正确的Owner,复用已有的ViewModel
    val exampleViewModel = viewModel(factory = ExampleViewModelFactory(application))

    // 业务逻辑代码...
}

// 修正后的Factory类
class ExampleViewModelFactory(private val application: Application) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ExampleViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return ExampleViewModel(application) as T
        }
        throw IllegalArgumentException("无法识别的ViewModel类")
    }
}

方式二:在Activity的onCreate中初始化

如果需要在Activity层面提前初始化ViewModel,直接用Activity本身作为ViewModelStoreOwner(Activity本身实现了这个接口):

class MainActivity : ComponentActivity() {
    private lateinit var exampleViewModel: ExampleViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val application = application
        // 用Activity作为Owner,确保ViewModel绑定到跨配置变更的Store
        exampleViewModel = ViewModelProvider(this, ExampleViewModelFactory(application))[ExampleViewModel::class.java]

        setContent {
            ExampleScreen(viewModel = exampleViewModel)
        }
    }
}

@Composable
fun ExampleScreen(viewModel: ExampleViewModel) {
    // 使用传入的ViewModel...
}

核心原理提醒

ViewModel的持久化完全依赖于ViewModelStoreOwner的生命周期:只有Owner在配置变更时不被销毁(比如Activity、Fragment),对应的ViewModelStore才会被保留,ViewModel实例也就不会重建。使用Factory时,只要Owner正确、key一致(默认用ViewModel类名,无需手动指定),就会复用已有的实例,Factory仅在首次创建ViewModel时被调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:30:25