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

如何注入泛型类型?Hilt泛型仓库依赖注入报错问题

Hilt泛型仓库依赖注入编译错误解决方案

问题背景

泛型仓库接口与实现

定义泛型仓库接口AuthRepo<R>:

interface AuthRepo<R> {
    val isUserAuthenticatedInFirebase: Boolean
    suspend fun oneTapSignInWithGoogle(): R
    suspend fun firebaseSignInWithGoogle(): R
}

实现类AuthRepoImpl,依赖注入两个命名的BeginSignInResult实例:

@Singleton
class AuthRepoImpl @Inject constructor(
   ...
   @Named(SING_IN_RESULT)
   private val singInResult: BeginSignInResult,
   @Named(SING_UP_RESULT)
   private val singUpResult: BeginSignInResult,
   ...
) : AuthRepo<BeginSignInResult>

Hilt绑定模块

通过AuthModule绑定仓库实现:

@Module
@InstallIn(ViewModelComponent::class)
abstract class AuthModule {
    @Binds
    abstract fun provideAuthRepository(
        authRepoImpl: AuthRepoImpl
    ): AuthRepo<BeginSignInResult>
}

非自定义类的注入逻辑

由于BeginSignInResult是非自定义类,通过挂起函数提供实例:

@Provides
@Named(AuthConstant.SING_IN_RESULT)
suspend fun provideSingInResult(
    oneTapClient: SignInClient,
    @Named(AuthConstant.SIGN_IN_REQUEST)
    signUpRequest: BeginSignInRequest
) : BeginSignInResult {
    return oneTapClient.beginSignIn(signUpRequest).await()
}

@Provides
@Named(AuthConstant.SING_UP_RESULT)
suspend fun provideSingUpResult(...) : BeginSignInResult ...

编译错误信息

com...AuthRepo<com...BeginSignInResult> cannot be provided without an @Provides-annotated method.
com...AuthRepo<com..BeginSignInResult> is injected at
com...OneTapSingInUseCase(authRepo)
com...OneTapSingInUseCase<com...BeginSignInResult> is injected at
com...AuthRepo<com....BeginSignInResult> is injected at
com...OneTapSingInUseCase(authRepo)
com...OneTapSingInUseCase<com...BeginSignInResult> is injected at
com...LoginViewModel(�, oneTapUseCase)
com...LoginViewModel is injected at
com...LoginViewModel_HiltModules.BindsModule.binds(arg0)
@dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at
dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com....App_HiltComponents.SingletonC ? com...App_HiltComponents.ActivityRetainedC ? com...App_HiltComponents.ViewModelC]

解决方案

1. 修复组件作用域不匹配问题

AuthRepoImpl标注了@Singleton(归属SingletonComponent),但绑定它的AuthModule安装在ViewModelComponent,作用域不兼容导致Hilt无法解析依赖。

修复方式二选一:

  • 将AuthModule的@InstallIn改为SingletonComponent:
    @Module
    @InstallIn(SingletonComponent::class)
    abstract class AuthModule {
        @Binds
        abstract fun provideAuthRepository(
            authRepoImpl: AuthRepoImpl
        ): AuthRepo<BeginSignInResult>
    }
    
  • 或移除AuthRepoImpl的@Singleton,改用@ViewModelScoped:
    @ViewModelScoped
    class AuthRepoImpl @Inject constructor(
       ...
       @Named(SING_IN_RESULT)
       private val singInResult: BeginSignInResult,
       @Named(SING_UP_RESULT)
       private val singUpResult: BeginSignInResult,
       ...
    ) : AuthRepo<BeginSignInResult>
    

2. 修正挂起函数注入的逻辑问题

Hilt不支持直接注入suspend函数提供的实例(注入过程为同步),且BeginSignInResult是登录操作的动态结果,不适合作为构造参数注入(注入实例为一次性,无法满足每次登录获取新结果的需求)。

正确做法:将获取BeginSignInResult的逻辑移到仓库方法中,直接注入依赖的SignInClient和BeginSignInRequest:

@Singleton
class AuthRepoImpl @Inject constructor(
    private val oneTapClient: SignInClient,
    @Named(AuthConstant.SIGN_IN_REQUEST)
    private val signInRequest: BeginSignInRequest,
    @Named(AuthConstant.SIGN_UP_REQUEST)
    private val signUpRequest: BeginSignInRequest,
    ...
) : AuthRepo<BeginSignInResult> {
    override suspend fun oneTapSignInWithGoogle(): BeginSignInResult {
        return oneTapClient.beginSignIn(signInRequest).await()
    }

    // 同理实现其他登录方法
}

3. 检查命名常量拼写错误

代码中存在SING_IN_RESULT与SIGN_IN_REQUEST的拼写差异(SING vs SIGN),需确保所有@Named注解的常量字符串完全一致,避免Hilt无法匹配依赖。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:10:33