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
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 the sample/multi-module in case someone wants to try out.
/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)
@AppScope
@Component(dependencies = [CoreComponent::class])
interface AppComponent {
fun inject(app: MainApp)
@Component.Factory
interface Factory {
fun create(
coreComponent: CoreComponent
): AppComponent
}
}
@Singleton
@Component
interface CoreComponent {
fun providerContext(): Context
@Component.Factory
interface Factory {
fun create(
@BindsInstance applicationContext: Context
): CoreComponent
}
}
@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)
}
@Module
class FeatureModule {
@Provides
fun provideVM(activity: FeatureActivity): FeatureViewModel {
val vm by activity.scopedComponent {
FeatureViewModel()
}
return 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.
@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
}
}