Room+MVVM架构TodoList应用:ViewModel无无参构造函数报错
别担心,这个问题在刚接触MVVM和Room的开发者中非常常见,我来一步步帮你理清问题并解决它。
问题原因分析
从报错信息里的关键提示:
java.lang.Class<com.robybp.todolist.view_models.TaskViewModel> has no zero argument constructor
可以看出,你的TaskViewModel继承了AndroidViewModel,这个类要求构造函数必须接收Application类型的参数;但你使用默认的ViewModelProvider(this)时,ViewModelProvider会默认调用NewInstanceFactory,它尝试用无参构造函数来创建ViewModel实例,这就和你的ViewModel构造要求冲突了,所以抛出了异常。
解决方案
你需要使用专门为AndroidViewModel设计的AndroidViewModelFactory来创建实例,它会自动帮你传入Application对象。
方法1:手动指定ViewModelFactory
修改你MainFragment中onViewCreated里的ViewModel初始化代码:
原来的代码:
sharedTaskViewModel = ViewModelProvider(this).get(TaskViewModel::class.java)
替换为:
sharedTaskViewModel = ViewModelProvider( this, ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application) ).get(TaskViewModel::class.java)
方法2:使用ViewModel KTX扩展(更简洁)
如果你的项目已经引入了AndroidX ViewModel的KTX依赖(大部分现代Android项目都会包含),可以用委托方式来简化代码,直接在Fragment类中声明:
private val sharedTaskViewModel: TaskViewModel by viewModels()
这样就不需要手动写ViewModelProvider的代码了,系统会自动使用正确的AndroidViewModelFactory来创建符合要求的ViewModel实例。
验证你的ViewModel代码
你的TaskViewModel代码是完全正确的:
- 继承了
AndroidViewModel并接收Application参数 - 在
init块中正确初始化了Room数据库、Repository和LiveData - 使用
viewModelScope来执行异步数据库操作,符合MVVM的最佳实践
内容的提问来源于stack exchange,提问作者Robert Baricevic-Petrus

