Multiple @Binds with the same return class, but with a different key

All of the following are used with dagger 2.10 and dagger.android .

Let's say I have a class that I would like to introduce in several actions.

 public class DemoSharedClass { Activity activity; @Inject public DemoSharedClass(Activity activity) { this.activity = activity; } } 

Then, using the latest Dagger APIs, my classes are defined as

 public class DemoActivity extends DaggerActivity { @Inject DemoSharedClass demoSharedClass; // ... } public class Demo2Activity extends DaggerActivity { @Inject DemoSharedClass demoSharedClass; // ... } 

Each action has its own module and subcomponent defined as (the same for Demo2Activity )

 @Module(subcomponents = DemoActivitySubcomponent.class) public abstract class DemoActivityModule { @Binds @IntoMap @ActivityKey(DemoActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindDemoActivityInjectorFactory(DemoActivitySubcomponent.Builder builder); // This is set so SharedClass can be injected using its constructor // There is the same in Demo2ActivityModule @Binds abstract Activity bindActivity(DemoActivity demoActivity); } @Subcomponent public interface DemoActivitySubcomponent extends AndroidInjector<DemoActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<DemoActivity> {} } 

Finally, an application component is defined as

 @Component(modules = { ApplicationModule.class, AndroidInjectionModule.class, DemoActivityModule.class, Demo2ActivityModule.class, }) interface DemoApplicationComponent { DemoApplication injectApplication(DemoApplication application); } 

Now I get this error when creating a project:

 Error:(11, 11) error: [dagger.android.AndroidInjector.inject(T)] android.app.Activity is bound multiple times: @Binds android.app.Activity dagger.demo.DemoActivityModule.bindActivity(dagger.demo.DemoActivity) @Binds android.app.Activity dagger.demo.Demo2ActivityModule.bindActivity(dagger.demo.Demo2Activity) 

I get an error, and I think that is because they are in the same area as the application component.

I was thinking of creating a common module for both DemoSubcomponents, which would look something like this, but with a similar error.

 @Module public abstract class SharedClassModule { @Binds abstract Activity bindContext(DemoActivity demoActivity); @Binds abstract Activity bindContext(Demo2Activity demo2Activity); } 

Question: How should I do this?

+2
android dagger-2
source share
1 answer

Each subcomponent will need a separate binding:

 @Module interface DemoActivitySubcomponentModule { @Binds abstract Activity bindContext(DemoActivity demoActivity); // ...other bindings unique to DemoActivity and not DemoActivity2 } @Subcomponent(modules={DemoActivitySubcomponentModule.class}) public interface DemoActivitySubcomponent extends AndroidInjector<DemoActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<DemoActivity> {} } 

Due to the @BindsInstance Builder seedInstance(DemoActivity) in AndroidInjector.Builder , which Dagger calls in AndroidInjector.Builder.create() from DispatchingAndroidInjector , the Dagger really knows how to provide an instance of DemoActivity at least. However, there is no built-in binding between DemoActivity and Activity (or context), so the binding should be done in a subcomponent, not in a component. By placing the module with this binding on the corresponding @Subcomponent , you can make sure that in each corresponding subcomponent, the Activity binding switches to the correct type that the dagger knows about.

Note that the @Binds @IntoMap @ActivityKey(...) binding in the DemoActivityModule must still be included in the ApplicationComponent, so the ApplicationComponent can determine which subcomponent will be created from the class of the input Activity. You specifically want the new DemoActivitySubcomponentModule to switch to DemoActivitySubcomponent so that it activates the Activity-to-DemoActivity in a place where DemoActivity2Subcomponent cannot see it.

As a side note, the problem you see is the conflict between two Activity bindings that occur in the same component. It is not entirely correct to say the same scope because (although you can add an area annotation such as @ActivityScope for each subcomponent), there is no area annotation that will help you here. seedInstance will be applied only within each subcomponent that is not associated with the display, which will be combined with relationships in the components of the ancestor, as well as with components specific to subcomponents.

+5
source share

All Articles