1

I'm attempting to inject the context of my MainActivity into a method. This is a simplified version of my Dagger setup:

AppComponent

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        MainActivityModule::clas
    ]
)
interface AppComponent : AndroidInjector<MyApp> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        fun build(): AppComponent
    }
}

AppModule

class AppModule {
    @Singleton
    @Provides
    fun provideRepository(context: Context) = Repository(context)
}

MainActivityModule

@Suppress("unused")
@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity


    @Binds
    abstract fun bindsMainActivityContext(mainActivity: MainActivity): @ActivityContext Context
}

as you can see in provideRepository() there's an argument context that should be injected. Whenever I build the app the following error appears:

error: [Dagger/MissingBinding] app.example.myapp.MainActivity cannot be provided without an @Inject constructor or an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
public abstract interface AppComponent extends dagger.android.AndroidInjector<app.example.myapp.MyApp> {
                ^
  A binding with matching key exists in component: app.example.myapp.injection.module.MainActivityModule_ContributeMainActivity.MainActivitySubcomponent
      app.example.myapp.MainActivity is injected at
          app.example.myapp.injection.module.MainActivityModule.bindsMainActivityContext(mainActivity)
      @app.example.myapp.injection.module.ActivityContext android.content.Context is injected at
          app.example.myapp.injection.module.AppModule.provideTokenRepository(…, context)
      app.example.myapp.repository.interfaces.ITokenRepository is injected at
          app.example.myapp.ui.signin.SignInViewModel(repository)
      app.example.myapp.ui.signin.SignInViewModel is injected at
          app.example.myapp.injection.module.ViewModelModule.bindSignInViewModel(signInViewModel)
      java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
          app.example.myapp.injection.ViewModelFactory(creators)
      app.example.myapp.injection.ViewModelFactory is injected at
          app.example.myapp.injection.module.ViewModelModule.bindViewModelFactory(factory)
      androidx.lifecycle.ViewModelProvider.Factory is injected at
          app.example.myapp.MainActivity.viewModelFactory
      app.example.myapp.MainActivity is injected at
          dagger.android.AndroidInjector.inject(T) [app.example.myapp.injection.AppComponent → app.example.myapp.injection.module.MainActivityModule_ContributeMainActivity.MainActivitySubcomponent]
  The following other entry points also depend on it:
      dagger.android.AndroidInjector.inject(T) [app.example.myapp.injection.AppComponent → app.example.myapp.injection.module.FragmentModule_ContributeMainFragment.MainFragmentSubcomponent]
      dagger.android.AndroidInjector.inject(T) [app.example.myapp.injection.AppComponent → app.example.myapp.injection.module.FragmentModule_ContributeSignInFragment.SignInFragmentSubcomponent]

As you can see from the error Dagger seems to be able to trace from the context to the root of the app but for some reason I get the above error.

Is there anything I have done wrong? Thanks

Pav Sidhu
  • 6,724
  • 18
  • 55
  • 110
  • [Check this](https://stackoverflow.com/q/44912080/1837367) for some info and solutions on your problem. It seems like you're trying to use `MainActivity ` from `MainActivityModule`, but you added the module to your `@Singleton AppComponent`, where you don't have access to the activitiy. – David Medenjak Aug 25 '19 at 06:46
  • @DavidMedenjak After reasoning that post I'm still unable to figure out the issue, would you be able to expand? – Pav Sidhu Aug 25 '19 at 17:12
  • Could you please include `MainActivityModule` in your question? – David Medenjak Aug 25 '19 at 17:31
  • @DavidMedenjak sure just included it in the question – Pav Sidhu Aug 25 '19 at 17:52

2 Answers2

0

You're trying to @Binds MainActivity from a module which you add to your AppComponent. That won't work, because there is no MainActivity (as the error states).

@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity

    // there is no MainActivity here (in AppComponent)
    @Binds
    abstract fun bindsMainActivityContext(mainActivity: MainActivity): @ActivityContext Context
}

It seems like what you wanted to do is bind MainActivity as Context in your MainActivity's Subcomponent, e.g. like the following. You'll need a second module which you then add to the subcomponent:

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        ActivityModule::clas  // bind module with subcomponents instead, see next
    ]
)
interface AppComponent // ...

// Activity module that you can add to AppComponent with subcomponents
@Module
abstract class ActivityModule {

    // bind the module with the bindings here
    @ContributesAndroidInjector(modules = [MainActivityModule::class])
    abstract fun contributeMainActivity(): MainActivity

}

// now we bind it to the MainActivity Subcomponent _only_ and it will work
@Module
abstract class MainActivityModule {

    @Binds
    abstract fun bindsMainActivityContext(mainActivity: MainActivity): @ActivityContext Context
}
David Medenjak
  • 33,993
  • 14
  • 106
  • 134
  • Appreciate your help, even with these changes I receive the same error `[Dagger/MissingBinding] android.content.Context cannot be provided without an @Provides-annotated method.` – Pav Sidhu Aug 26 '19 at 13:47
  • @PavSidhu could you maybe include the _full_ error stack message? – David Medenjak Aug 26 '19 at 13:54
  • @PavSidhu Now it's complaining that there is no Context available in `@Singleton` which is needed for your repository which is injected into your ViewModel. You'll need to bind the Application context in your App component to have access to a context. It's best you take some time to try and read the error message, it shows exactly what Dagger is missing where – David Medenjak Aug 27 '19 at 10:29
0

According to the error, dagger dont know how to provide this dependency, either you have missed @Inject annotation in dependency or you might have forgot to provide dependency with @Provides annotation

Dharman
  • 30,962
  • 25
  • 85
  • 135
dalakoti07
  • 1
  • 1
  • 2
  • Or maybe you missed add the module class in the app Component component annotation, not related to OP, but it can happen – ruif3r Mar 17 '22 at 03:38