简体   繁体   中英

Dagger2 - Multi Module - A binding with matching key exists in component

Background

I am trying to use dagger in a multi module setup. One of my aim is to reduce the number of components being used. So basically aiming for 1 component per feature module.

Setup core->app->feature

Problem

Dagger fails with the exception A binding with matching key exists in component: which refers to that I have bound a dependency somewhere in my entire object graph but it cannot be reached.

But for my scenario I am creating the sub-component in my activity and calling inject to make sure the component has the access to my activity. This atleast in my understanding should be accessible but it's still not able to provide the dependency of my viewmodel.

Here is thesample/multi-module in case someone wants to try out.

Stacktrace

/Users/feature1/build/**/FeatureComponent.java:8: error: [Dagger/MissingBinding]
com.**.FeatureActivity 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 FeatureComponent {
                ^
  A binding with matching key exists in component: com.**.FeatureComponent
      com.**.FeatureActivity is injected at
          com.**.FeatureModule.provideVM(activity)
      com.**.FeatureViewModel is injected at
          com.**.FeatureActivity.vm
      com.**.FeatureActivity is injected at
          com.**.FeatureComponent.inject(com.**.FeatureActivity)

AppComponent

@AppScope
@Component(dependencies = [CoreComponent::class])
interface AppComponent {

    fun inject(app: MainApp)

    @Component.Factory
    interface Factory {
        fun create(
            coreComponent: CoreComponent
        ): AppComponent
    }
}

CoreComponent

@Singleton
@Component
interface CoreComponent {

    fun providerContext(): Context

    @Component.Factory
    interface Factory {
        fun create(
            @BindsInstance applicationContext: Context
        ): CoreComponent
    }
}

FeatureComponent

@Component(
    modules = [FeatureModule::class],
    dependencies = [CoreComponent::class]
)
@FeatureScope
interface FeatureComponent {

    // Planning to use this component as a target dependency for the module.
    fun inject(activity: FeatureActivity)
}

Feature Module

@Module
class FeatureModule {

    @Provides
    fun provideVM(activity: FeatureActivity): FeatureViewModel {
        val vm by activity.scopedComponent {
            FeatureViewModel()
        }
        return vm
    }
}

Feature VM

class FeatureViewModel @Inject constructor(): ViewModel() 

Since I'm using activity to provide my viewModel I will have to use @BindsInstance to bind the instance of any activity or fragment that I want to inject.

In short if I change my feature component to the following code it starts to work where I bind the instance of the activity at the creation of the component.

PS: If anyone knows a better to inject the fragment at later stage with just using one component, please feel free to improve this answer.

FeatureComponent

@Component(
    modules = [FeatureModule::class],
    dependencies = [CoreComponent::class]
)
@FeatureScope
interface FeatureComponent {

    fun inject(activity: FeatureActivity)

    @Component.Factory
    interface Factory {
        fun create(
            @BindsInstance applicationContext: FeatureActivity,
            coreComponent: CoreComponent,
        ): FeatureComponent
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM