Activity重建时Fragment无法获取Activity创建的带参ViewModel
解决Activity重建后Fragment无法获取带参ViewModel的问题
咱们先把问题根源捋清楚:
当Activity因为系统语言切换、权限变更这类配置变更重建时,之前的代码逻辑会出状况——首次启动时Fragment能拿到ViewModel,是因为Activity已经用Factory创建好了实例,系统直接复用;但重建后,新的Activity实例如果没正确用Factory初始化ViewModel,或者Fragment获取时没指定Factory,系统会尝试调用MessageViewModel的无参构造,可你的ViewModel只有带参构造,自然就报无法实例化的错误了。
一步步解决方案
1. 先确认你的Factory实现没问题
首先得保证MessageVMFactory能正确创建MessageViewModel,示例代码如下:
class MessageVMFactory : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(MessageViewModel::class.java)) { @Suppress("UNCHECKED_CAST") return MessageViewModel(MutableLiveData()) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
2. Activity重建时必须用Factory获取ViewModel
在Activity的onCreate方法里,不管是不是重建场景,都要通过指定Factory来获取ViewModel,不能省略Factory参数:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 不管是首次启动还是重建,都用Factory获取ViewModel val viewModel = ViewModelProviders.of(this, MessageVMFactory()) .get(MessageViewModel::class.java) }
3. Fragment获取ViewModel时也要指定Factory
Fragment里不能只传activity就完事,必须同时带上Factory,这样才能确保拿到的是Activity层级的正确ViewModel实例:
// 在Fragment的onViewCreated或者onActivityCreated方法中 val viewModel = ViewModelProviders.of(requireActivity(), MessageVMFactory()) .get(MessageViewModel::class.java)
额外说明
可能你会好奇为啥首次启动没问题?因为首次启动时Activity先通过Factory创建了ViewModel,Fragment去获取时系统直接返回已存在的实例,不需要调用构造函数;但重建时原ViewModel的状态没法自动恢复(因为带参构造需要Factory来初始化),这时候没指定Factory的话,系统就不知道怎么创建新实例,所以报错。
内容的提问来源于stack exchange,提问作者Kumar Purushottam
相关产品推荐
相关产品推荐

