Search code examples
androiddependency-injectiondagger-2

Dagger fails after migrating to 2.17


I've two modules :app and :settings. Here are my dagger configuration.

My component:

@ApplicationScope
@Component(
    modules = [
        AndroidInjectionModule::class,
        AndroidSupportInjectionModule::class,
        RoutingModule::class,
        SettingsModule::class
    ]
)
interface ELanguageComponent {

    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: Application): Builder
        fun build(): ELanguageComponent
    }

    fun inject(application: BaseELanguageApplication)
}

The RoutingModule:

@Module
class RoutingModule {

    @Provides
    fun ProvidesettingsFragmentRouter(router: SettingsRouter): SettingsFragment.Router = router
}

The SettingsRouter:

class SettingsRouter @Inject constructor(
    private val applicationStateManager: ApplicationStateManager
) : SettingsFragment.Router

The SettingsModule:

@Module
abstract class SettingsModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = [SettingsFragmentModule::class, ApplicationStateManagerModule::class])
    abstract fun settingsActivity(): SettingsActivity
}

@Module
abstract class ApplicationStateManagerModule {

    @Module
    companion object {

        @JvmStatic
        @Provides
        fun bindApplicationStateManager(settingsActivity: SettingsActivity): ApplicationStateManager = settingsActivity
    }
}

My SettingsFragmentModule:

@Module
abstract class SettingsFragmentModule {

    @FragmentScope
    @ContributesAndroidInjector
    abstract fun settingsFragment(): SettingsFragment
}

And the SettingsFragment.Router is injected inside my SettingsFragment:

class SettingsFragment : DaggerFragment() {

  @Inject
  lateinit var router: Router
  
  ...
}

I've already found and read this article but it does not help much since the error is not that explanatory:

[Dagger/MissingBinding] com.altissia.common.authentication.ApplicationStateManager cannot be provided without an @Provides-annotated method. public abstract interface ELanguageComponent { ^ com.altissia.common.authentication.ApplicationStateManager is injected at com.altissia.router.SettingsRouter(applicationStateManager, …) com.altissia.router.SettingsRouter is injected at com.altissia.injection.module.RoutingModule.ProvidesettingsFragmentRouter(router) com.altissia.settings.fragment.SettingsFragment.Router is injected at com.altissia.settings.fragment.SettingsFragment.router com.altissia.settings.fragment.SettingsFragment is injected at dagger.android.AndroidInjector.inject(T) [com.altissia.injection.component.ELanguageComponent → com.altissia.settings.injection.module.SettingsModule_SettingsActivity.SettingsActivitySubcomponent → com.altissia.settings.injection.module.SettingsFragmentModule_SettingsFragment.SettingsFragmentSubcomponent]

What am I missing here? ApplicationStateManager is provided through the ApplicationStateManagerModule which is installed inside SettingsModule.


Solution

  • The situation in the linked article applies here.

    • SettingsFragment requests a SettingsFragment.Router.
    • SettingsFragment.Router depends on SettingsRouter, and this binding is in the application component.
    • SettingsRouter depends on ApplicationStateManager via an @Inject constructor.
    • The ApplicationStateManager binding is in your (generated) activity subcomponent.

    Thus, you have a binding in the parent component which requires a binding in a subcomponent. As described in the article, the easiest way to fix this is to move RoutingModule into your activity (or fragment) subcomponent.