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

使用Nav-graph作用域ViewModel与AbstractSavedStateViewModelFactory时出现SavedStateProvider重复注册异常求助

解决Nav-Graph作用域ViewModel结合AbstractSavedStateViewModelFactory的崩溃问题

我之前也碰到过类似的情况,你这个崩溃的核心原因其实是错误地把Activity作为SavedStateRegistryOwner传给了AbstractSavedStateViewModelFactory,和常见的重复注册场景本质不同,下面给你拆解原因和修复步骤:

问题根源

导航图作用域的ViewModel,它的生命周期是和对应的NavBackStackEntry(也就是导航图的后台栈条目)绑定的,而不是Activity。当你第一次进入FirstPageFragment时,你的Factory把SavedStateProvider注册到了Activity的SavedStateRegistry里;当你返回StartFragment,导航图的NavBackStackEntry会被销毁,但Activity的SavedStateRegistry中注册的Provider并不会随之移除;等你再次进入FirstPageFragment时,新的Factory又尝试注册同一个key的Provider,直接触发了「给定key的SavedStateProvider已注册」的异常。

修复步骤

1. 调整ViewModel Factory的构造逻辑

首先修改MyViewModel.Factory,不再依赖Activity,而是直接接收SavedStateRegistryOwner和Application(避免不必要的Activity引用):

class MyViewModel(application: Application, savedStateHandle: SavedStateHandle, val someString: String) : AndroidViewModel(application){ 
    class Factory(
        private val owner: SavedStateRegistryOwner,
        private val application: Application,
        private val someString: String
    ) : AbstractSavedStateViewModelFactory(owner, null) { 
        override fun <T : ViewModel?> create( 
            key: String, 
            modelClass: Class<T>, 
            handle: SavedStateHandle 
        ): T { 
            if (modelClass.isAssignableFrom(MyViewModel::class.java)) { 
                @Suppress("UNCHECKED_CAST") 
                return MyViewModel(application, handle, someString) as T 
            } 
            throw IllegalArgumentException("Unable to construct viewmodel") 
        } 
    } 
    // ... 其他ViewModel逻辑
}

2. 传入正确的SavedStateRegistryOwner到Factory

在FirstPageFragment中,navGraphViewModels的lambda参数会提供当前导航图对应的ViewModelStoreOwner,而这个Owner其实就是NavBackStackEntry(同时也是SavedStateRegistryOwner),我们直接用它来创建Factory:

class FirstPageFragment: Fragment() { 
    private val myViewModel: MyViewModel by navGraphViewModels(R.id.nav_mission) { owner ->
        // owner 是导航图对应的NavBackStackEntry,它才是当前ViewModel的正确SavedStateRegistryOwner
        MyViewModel.Factory(owner, requireActivity().application, "hello world1") 
    } 
    // ... 其他Fragment逻辑
}

为什么这样能解决问题?

修改后,SavedStateProvider会被注册到导航图的NavBackStackEntry的SavedStateRegistry中,当你返回StartFragment导致导航图的BackStackEntry销毁时,对应的Provider也会被自动移除。再次进入导航图时,新的BackStackEntry会创建新的Provider,自然不会出现重复注册的冲突了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 21:54:06