Hilt报错:ActivityContext无法提供,求适配CredentialManager的Activity Context
Hilt中ActivityRetainedComponent无法获取Activity Context的解决办法
问题场景
我按如下方式配置Hilt模块:
@Module @InstallIn(ActivityRetainedComponent::class) object CredentialModule { @Provides @ActivityRetainedScoped fun provideActivityContext( @ActivityContext context: Context ) = context @Provides @ActivityRetainedScoped fun provideFirebaseAuth(): FirebaseAuth = FirebaseAuth.getInstance() @Provides @ActivityRetainedScoped fun provideCredentialManager( context: Context ): CredentialManager = CredentialManager.create(context) @Provides @ActivityRetainedScoped fun provideGetGoogleIdOption( context: Context ): GetGoogleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) .setServerClientId(context.getString(R.string.web_client_id)) .setAutoSelectEnabled(false) .build() @Provides @ActivityRetainedScoped fun provideGetCredentialRequest( getGoogleIdOption: GetGoogleIdOption ) = GetCredentialRequest.Builder() .addCredentialOption(getGoogleIdOption) .build() @Provides @ActivityRetainedScoped fun provideAuthDataSource( context: Context, auth: FirebaseAuth, credentialManager: CredentialManager, getCredentialRequest: GetCredentialRequest ) = AuthDataSource(context, auth, credentialManager, getCredentialRequest) }
但始终抛出如下错误:
error: [Dagger/MissingBinding] @dagger.hilt.android.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method. public abstract static class SingletonC implements ProfileApp_GeneratedInjector, ^ @dagger.hilt.android.qualifiers.ActivityContext android.content.Context is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityRetainedC] com.being.coder.app.profile.di.CredentialModule.provideActivityContext(context) android.content.Context is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityRetainedC] com.being.coder.app.profile.di.CredentialModule.provideAuthDataSource(context, �) com.being.coder.app.profile.data.datasource.AuthDataSource is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityRetainedC] com.being.coder.app.profile.di.CredentialModule.provideAuthRepository(authDataSource) com.being.coder.app.profile.presentation.signin.repository.AuthRepository is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityRetainedC] com.being.coder.app.profile.di.CredentialModule.provideAuthUseCases(authRepository) com.being.coder.app.profile.domain.usecase.auth.AuthUseCases is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ViewModelC] com.being.coder.app.profile.ui.screens.auth.AuthViewModel(authUseCases) com.being.coder.app.profile.ui.screens.auth.AuthViewModel is injected at [com.being.coder.app.profile.ProfileApp_HiltComponents.ViewModelC] com.being.coder.app.profile.ui.screens.auth.AuthViewModel_HiltModules.BindsModule.binds(arg0) @dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.Class<?>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at [com.being.coder.app.profile.ProfileApp_HiltComponents.ViewModelC] dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.being.coder.app.profile.ProfileApp_HiltComponents.SingletonC ? com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityRetainedC ? com.being.coder.app.profile.ProfileApp_HiltComponents.ViewModelC] Note: @dagger.hilt.android.qualifiers.ActivityContext android.content.Context is provided in the following other components: [com.being.coder.app.profile.ProfileApp_HiltComponents.ActivityC] dagger.hilt.android.internal.modules.ActivityModule.provideContext(�)
我曾尝试使用@ApplicationContext解决问题,但CredentialManager.create(context)需要Activity Context,请问如何在当前场景下获取Activity Context以消除报错?
解决方案
核心原因
ActivityRetainedComponent的生命周期跨Activity配置变更(比如屏幕旋转),它不依赖具体的Activity实例,因此Hilt不会在这个组件中提供@ActivityContext的依赖——Activity Context仅在ActivityComponent及其子组件中可用。
具体实现步骤
拆分模块,分离Activity级依赖
将需要Activity Context的提供者(如CredentialManager、GetGoogleIdOption)移到安装在ActivityComponent的模块中:@Module @InstallIn(ActivityComponent::class) object ActivityAuthModule { @Provides @ActivityScoped fun provideCredentialManager( @ActivityContext context: Context ): CredentialManager = CredentialManager.create(context) @Provides @ActivityScoped fun provideGetGoogleIdOption( @ActivityContext context: Context ): GetGoogleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) .setServerClientId(context.getString(R.string.web_client_id)) .setAutoSelectEnabled(false) .build() @Provides @ActivityScoped fun provideGetCredentialRequest( getGoogleIdOption: GetGoogleIdOption ) = GetCredentialRequest.Builder() .addCredentialOption(getGoogleIdOption) .build() }调整ActivityRetained模块的依赖注入方式
保留跨配置保留的依赖(如FirebaseAuth、AuthDataSource)在原模块中,但通过Provider延迟获取Activity级别的依赖,避免生命周期不匹配导致的内存泄漏:@Module @InstallIn(ActivityRetainedComponent::class) object CredentialModule { @Provides @ActivityRetainedScoped fun provideFirebaseAuth(): FirebaseAuth = FirebaseAuth.getInstance() @Provides @ActivityRetainedScoped fun provideAuthDataSource( @ApplicationContext context: Context, auth: FirebaseAuth, credentialManager: Provider<CredentialManager>, getCredentialRequest: Provider<GetCredentialRequest> ) = AuthDataSource(context, auth, credentialManager.get(), getCredentialRequest.get()) }
关键说明
- 使用
Provider<T>可以让ActivityRetainedScoped的对象在需要时才获取Activity级别的实例,确保此时Activity仍然存活,避免持有已销毁的Activity引用。 - 如果
AuthDataSource中不会立即使用CredentialManager,建议在具体调用方法时再调用Provider.get(),进一步降低内存泄漏风险。
内容的提问来源于stack exchange,提问作者Arshad Ali
相关产品推荐
相关产品推荐

