如何注入泛型类型?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
相关产品推荐
相关产品推荐

