使用AbstractSavedStateViewModelFactory报已绑定生命周期所有者异常求助
问题根源
我之前遇到过几乎一模一样的问题,一眼就能看出问题出在哪!你触发的IllegalStateException: Already attached to lifecycleOwner异常,核心矛盾是你把Activity作为SavedStateRegistryOwner传给了AbstractSavedStateViewModelFactory,但ViewModel实际是和当前Fragment绑定的。
具体拆解下逻辑:
- 你在
TestStateAFragment的onCreate方法里,创建工厂时传入了activity as SavedStateRegistryOwner,这会让SavedStateHandle的生命周期和Activity绑定。 - 但紧接着你通过
ViewModelProviders.of(this, factory)把ViewModel和当前Fragment(代码里的this)绑定,这就导致SavedStateHandle被同时关联到两个不同的LifecycleOwner(Activity和Fragment)。当Fragment的生命周期触发绑定校验时,系统就会抛出“已绑定到其他LifecycleOwner”的异常。
至于SavedStateViewModelFactory能正常工作,是因为当你用ViewModelProviders.of(this)时,它默认会自动使用当前Fragment作为SavedStateRegistryOwner,不会出现生命周期绑定冲突。
修复步骤
只需要修改TestStateAFragment里创建工厂的代码,把传入的SavedStateRegistryOwner换成Fragment本身(this),同时可以把Fragment的arguments也传进去(方便ViewModel接收初始化参数):
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 把activity换成当前Fragment,同时传入arguments val factory = TestStateAViewModelFactory(this, arguments) viewModel = ViewModelProviders.of(this, factory).get(TestStateAViewModel::class.java) }
补充说明
从AndroidX Fragment 1.2.0版本开始,Fragment本身就实现了SavedStateRegistryOwner接口,所以直接传递this是完全安全且符合设计预期的。修改后,SavedStateHandle的生命周期会和Fragment保持一致,不会再出现绑定冲突的问题。
另外你提到的SavedStateViewModelFactory是final类、不支持非空构造的问题,用自定义的AbstractSavedStateViewModelFactory本来就是正确的解决方案,只要修正SavedStateRegistryOwner的传入对象就能正常使用了。
内容的提问来源于stack exchange,提问作者ashwin mahajan

