You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVVM架构下使用Hilt注入ViewModel遇绑定错误,求解决方案

问题:Hilt实现ViewModel依赖注入报错的解决方法

背景

APP采用MVVM架构,每个调用API的页面都存在重复代码:

val retrofitService = RetrofitService.getInstance(requireContext())
val mainRepository = MainRepository(retrofitService)
val viewModel =
ViewModelProvider(
viewOwner,
AppVMFactory(mainRepository)
)[AppViewModel::class.java]

为减少重复引入Hilt,已添加相关依赖、创建Application类与AppModule:

@Module
@InstallIn(SingletonComponent::class)
object AppModule{
    @Singleton
    fun provideApp(@ApplicationContext app: Context):BaseApplication = app as BaseApplication

    @Singleton
    @Provides
    fun someStr() = "Hello World from DI"
}

测试Activity成功注入字符串,但添加AppViewModel的提供方法后构建报错:

@Module
@InstallIn(SingletonComponent::class)
object AppModule{
....
    @Singleton
    @Provides
    fun vmSupport(context: Context, owner: ViewModelStoreOwner): AppViewModel {
        val retrofitService = RetrofitService.getInstance(context)
        val mainRepository = MainRepository(retrofitService)
        return ViewModelProvider(
            owner,
            AppVMFactory(mainRepository)
        )[AppViewModel::class.java]
    }
....

}

错误信息:

[Dagger/MissingBinding] android.content.Context cannot be provided without an @Provides-annotated method.
  public abstract static class SingletonC implements HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,
                         ^
      android.content.Context is injected at
          pkg.di.AppModule.vmSupport(context, …)
      pkg.viewModel.AppViewModel is injected at
          pkg.HomeScreen.vm
      pkg.HomeScreen is injected at
          pkg.HomeScreen_GeneratedInjector.injectHomeScreen(pkg.HomeScreen) [pkg.di.BaseApplication_HiltComponents.SingletonC → pkg.di.BaseApplication_HiltComponents.ActivityRetainedC → pkg.di.BaseApplication_HiltComponents.ActivityC]

Activity中使用@Inject lateinit var vm:AppViewModel注入,推测是参数传递问题,但不清楚正确实现方式。

相关类代码:

  • AppViewModel:
class AppViewModel(private val mainRepository: MainRepository) : ViewModel(){...}
  • MainRepository:
class MainRepository constructor(private val retrofitService: RetrofitService){...}
  • AppVMFactory:
class AppVMFactory(private val repository: MainRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return if (modelClass.isAssignableFrom(AppViewModel::class.java)) {
            AppViewModel(this.repository) as T
        } else {
            throw IllegalArgumentException("ViewModel Not Found")
        }
    }
}

错误原因

直接在SingletonComponent的Module中提供ViewModel实例的做法完全错误:

  1. ViewModel的生命周期由ViewModelStoreOwner(Activity/Fragment)管理,不能声明为@Singleton,否则会打破ViewModel的生命周期绑定规则。
  2. ViewModelStoreOwner属于Activity/Fragment层级组件,无法在全局单例的SingletonComponent中注入,两者生命周期不匹配。
  3. Context参数未添加@ApplicationContext注解,Hilt无法识别要注入的全局上下文实例。

正确实现步骤

1. 配置Hilt ViewModel依赖

确保已添加Hilt对ViewModel的支持依赖(若未添加):

implementation "com.google.dagger:hilt-android:2.48"
kapt "com.google.dagger:hilt-android-compiler:2.48"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
kapt "androidx.hilt:hilt-compiler:1.0.0"

2. 改造ViewModel,添加Hilt注解

给AppViewModel添加@HiltViewModel注解,并让构造函数使用@Inject标记:

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel

@HiltViewModel
class AppViewModel @Inject constructor(private val mainRepository: MainRepository) : ViewModel(){
    // 原有业务逻辑
}

注:新版本Hilt已弃用ViewModelInject,直接使用@Inject即可。

3. 在AppModule中提供底层依赖

只需要提供RetrofitService和MainRepository的实例,无需处理ViewModel的创建:

@Module
@InstallIn(SingletonComponent::class)
object AppModule{
    @Singleton
    @Provides
    fun provideRetrofitService(@ApplicationContext context: Context): RetrofitService {
        return RetrofitService.getInstance(context)
    }

    @Singleton
    @Provides
    fun provideMainRepository(retrofitService: RetrofitService): MainRepository {
        return MainRepository(retrofitService)
    }

    // 原有其他提供方法
    @Singleton
    @Provides
    fun someStr() = "Hello World from DI"
}

4. 在Activity/Fragment中注入ViewModel

使用by viewModels()委托获取ViewModel(需导入Hilt的ViewModel扩展):

import androidx.activity.viewModels
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class HomeScreen : AppCompatActivity() {
    // Hilt自动处理依赖注入,直接获取ViewModel
    private val vm: AppViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 正常使用vm即可
    }
}

Fragment同样需要添加@AndroidEntryPoint,根据需求选择by viewModels()(Fragment独立ViewModel)或by activityViewModels()(共享Activity的ViewModel)。

5. 废弃自定义ViewModelFactory

使用Hilt后,无需自己实现AppVMFactory,Hilt会自动生成对应的工厂类处理依赖注入逻辑。

关键说明

  • @HiltViewModel是Hilt识别ViewModel的核心标记,配合构造函数的@Inject,Hilt会自动将所需依赖注入到ViewModel中。
  • @AndroidEntryPoint必须添加到需要注入依赖的Activity/Fragment上,Hilt才能生成对应的注入代码。
  • ViewModel的生命周期与宿主绑定,绝不能在Singleton组件中提供,避免生命周期冲突导致的内存泄漏或数据异常。

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 06:24:47