androiddependency-injectiondaggerdagger-hilt

android.app.Activity cannot be provided without an @Provides-annotated method


I am trying to implement inapp-updates, I’ve Activity which has a ViewModel I added a method to it to “checkAppUpdates” which invokes “CheckAppUpdateUseCase” which take AppUpdateManager as a constructor parameter and then calls its checkForAppUpdates which do the actual checking for updates, the implementation needs either an instance of “Activity” or ”ActivityResultLauncher” to be passed to google’s AppUpdateManager’s startUpdateFlow or startUpdateFlowForResult method respectively my problrm is with injecting activity as a constructor parameter to my AppUpdateManager but it is not working, I am getting this build error >

MyApplication_HiltComponents.java:186: error: [Dagger/MissingBinding] @dagger.hilt.android.qualifiers.ActivityContext android.app.Activity cannot be provided without an @Provides-annotated method. public abstract static class SingletonC implements FragmentGetContextFix.FragmentGetContextFixEntryPoint,

Missing binding usage: @dagger.hilt.android.qualifiers.ActivityContext android.app.Activity is injected at com.my.app.AppUpdateManager(activity) com.my.app.AppUpdateManager is injected at com.my.app.CheckAppUpdateUseCase(appUpdateManager) com.my.app.CheckAppUpdateUseCase is injected at com.my.app.MainViewModel(…, checkAppUpdateUseCase, …) com.my.app.MainViewModel is injected at com.my.app.MainViewModel_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.my.app.MyApplication_HiltComponents.SingletonC → com.my.app.MyApplication_HiltComponents.ActivityRetainedC → com.my.app.MyApplication_HiltComponents.ViewModelC]

I've an activity like that

@AndroidEntryPoint
class MainActivity : AppCompatActivity(){

    private val viewModel by viewModels<MainViewModel>()
...

The viewmodel

@HiltViewModel class MainViewModel @Inject constructor( private val logoutUseCase: LogoutUseCase, private val checkAppUpdateUseCase: CheckAppUpdateUseCase, ...

The use-case

class CheckAppUpdateUseCase @Inject constructor(
    private val appUpdateManager: AppUpdateManager){

    suspend fun checkForAppUpdates() {
        appUpdateManager.checkForAppUpdates()
    }
}

The AppUpdateManager

private const val UPDATE_PRIORITY_HIGH = 4
class AppUpdateManager @Inject constructor(private val activity: Activity) {
    suspend fun checkForAppUpdates() {
        // use the activity here
    }
}

and I provide the AppUpdateManager like that

import android.app.Activity
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.qualifiers.ActivityContext
import com.my.app.AppUpdateManager

@Module
@InstallIn(ActivityComponent::class)
object UpdateManagerModule {

    @Provides
    fun provideActivity(@ActivityContext activity: Activity) = activity

    @Provides
    fun provideUpdateManager(@ActivityContext activity: Activity): AppUpdateManager {
         return AppUpdateManager(activity)
    }

}

I tried to inject the Activity directly to isolate the problem and commented the unnecessary code but I got the same error.


Solution

  • The Librarian's answer was helpful and it directed me to think about not using the ActivityContext in the ViewModel, but this SO Answer solved my problem by changing the activity dependency to context and then casting it to activity

    class AppUpdateManager @Inject constructor(@ActivityContext private val activityContext: Context) {
    

    And in module

    @Provides
    fun provideAppUpdateManager(@ActivityContext context: Context): AppUpdateManager =
        AppUpdateManager(context
    

    )