能否通过Hilt模块提供ViewModel而不使用注解?及报错排查
Hilt中ViewModel依赖注入的问题解答
1. 是否可以不使用注解实现ViewModel的依赖注入?
可以,但必须遵循ViewModel的生命周期管理规则。ViewModel不能像普通依赖对象那样直接通过Module提供实例,它必须由ViewModelProvider创建。因此需要让Hilt能够提供符合要求的ViewModelProvider.Factory,或者手动指定Factory来完成ViewModel的实例化与依赖注入。
2. 当前代码存在什么问题?
当前代码的核心问题是对Hilt管理ViewModel的逻辑理解有误:
hiltViewModel()这个Compose函数的默认实现依赖@HiltViewModel注解,它会尝试用Hilt生成的专属ViewModelFactory创建实例,而这个Factory要求ViewModel类必须带有@HiltViewModel且构造函数标注@Inject。- 你在Module中直接用
@Provides提供MainViewModel实例的方式完全错误——ViewModel不是普通依赖,它的生命周期由ViewModelProvider管控,Hilt不会用普通依赖注入的方式提供ViewModel实例。因此hiltViewModel()找不到正确的创建逻辑,会 fallback 尝试调用ViewModel的无参构造函数,而你的MainViewModel并没有定义无参构造,最终抛出NoSuchMethodException。
修正方案示例
如果要避开@HiltViewModel实现依赖注入,可以在Module中提供自定义的ViewModelProvider.Factory:
// Modules.kt @Module @InstallIn(SingletonComponent::class) object ViewModelsModule { @Provides fun provideAccountService(): AccountService = FirebaseAccountService() @Provides fun provideMainViewModelFactory(accountService: AccountService): ViewModelProvider.Factory { return object : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(MainViewModel::class.java)) { return MainViewModel(accountService) as T } throw IllegalArgumentException("Unknown ViewModel class") } } } } // AppComposable.kt @Composable fun AppComposable( viewModelFactory: ViewModelProvider.Factory = hiltViewModel() ) { val viewModel = viewModel<MainViewModel>(factory = viewModelFactory) // ... }
或者通过给ViewModel添加内部Factory类并注入依赖的方式实现:
// MainViewModel.kt class MainViewModel(private val accountService: AccountService) : ViewModel() { // ... class Factory @Inject constructor(private val accountService: AccountService) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { return MainViewModel(accountService) as T } } } // AppComposable.kt @Composable fun AppComposable( viewModelFactory: MainViewModel.Factory = hiltViewModel() ) { val viewModel = viewModel<MainViewModel>(factory = viewModelFactory) // ... }
内容的提问来源于stack exchange,提问作者asikorski
相关产品推荐
相关产品推荐

