Android报错:无法创建ViewModel实例,带Context构造的ViewModel求助
解决ViewModel实例化报错:java.lang.RuntimeException: Cannot create an instance of class ViewModel
你碰到的这个问题核心有两个原因:
- ViewModel带参数的构造函数不被默认工厂支持:默认的
ViewModelProvider.Factory只能创建无参构造的ViewModel实例,你的BooksFragmentViewModel有一个Context参数,所以默认工厂没办法完成实例化。 - 直接持有Context存在内存泄漏风险:ViewModel的生命周期通常比Fragment/Activity更长,如果持有组件级的Context,当组件被销毁时,ViewModel还可能存活,会导致Context无法被GC回收,引发内存泄漏。
下面给你两种可行的修复方案,优先推荐第二种更安全的实现:
方案一:自定义ViewModelFactory创建带参数的ViewModel
如果你确实需要传入Context,我们可以自定义一个ViewModel工厂类来处理带参数的实例化,但一定要传入Application Context来避免内存泄漏:
1. 编写自定义ViewModelFactory
class BooksViewModelFactory(private val application: Application) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(BooksFragmentViewModel::class.java)) { @Suppress("UNCHECKED_CAST") return BooksFragmentViewModel(application) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
2. 调整ViewModel构造函数
确保使用Application Context:
class BooksFragmentViewModel(application: Application) : ViewModel() { private val appContext = application.applicationContext var books: MutableLiveData<MutableList<BookItem>> = MutableLiveData() // 其他成员变量保留... init { books = bookRepo.booksGetRequest(appContext) } }
3. 在Fragment中用工厂实例化ViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 通过自定义工厂创建ViewModel booksModel = ViewModelProvider( this, BooksViewModelFactory(requireActivity().application) ).get(BooksFragmentViewModel::class.java) // 其他业务逻辑... }
方案二:使用AndroidViewModel(官方推荐)
AndroidViewModel是ViewModel的子类,它自带Application引用,无需手动传入Context,这是官方推荐的方式,能彻底规避内存泄漏问题:
1. 修改ViewModel继承AndroidViewModel
class BooksFragmentViewModel(application: Application) : AndroidViewModel(application) { private val appContext = application.applicationContext var books: MutableLiveData<MutableList<BookItem>> = MutableLiveData() // 其他成员变量保留... init { books = bookRepo.booksGetRequest(appContext) } }
2. 在Fragment中实例化ViewModel
AndroidViewModel可以直接通过默认工厂创建,不需要自定义工厂:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) booksModel = ViewModelProvider(this).get(BooksFragmentViewModel::class.java) // 其他业务逻辑... }
额外提醒
- 你Fragment里原来的
setContext方法可以删掉了,我们已经通过安全的方式获取到了Application Context。 - Volley的RequestQueue建议用Application Context创建,并且最好做成全局单例,避免重复创建造成资源浪费。
内容的提问来源于stack exchange,提问作者Razvan Andrei
相关产品推荐
相关产品推荐

