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

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及其子组件中可用。

具体实现步骤

  1. 拆分模块,分离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()
    }
    
  2. 调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:52:32