84401

Multiple @Binds with same return class but different key

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

Say I have a class I'd like to inject in multiple activities.

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 activity has its module and subcomponent define as (exactement 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, the app 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 I build the 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 the error, and I think this is because they are in the same scope, the app component.

I thought about creating a common module to both DemoSubcomponents which would look something like the following but with similar error.

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

Question: how am I supposed to do it?

Answer1:

You'll need a separate binding on each Subcomponent:

@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> {} }

Because of @BindsInstance Builder seedInstance(DemoActivity) in AndroidInjector.Builder, which Dagger calls in AndroidInjector.Builder.create() from DispatchingAndroidInjector, Dagger does know how to provide a DemoActivity instance at least. However, there's no built-in binding between DemoActivity and Activity (or Context), so the binding has to be made on the subcomponent instead of the component. By putting the module with that binding on the appropriate @Subcomponent, you can ensure that within each respective subcomponent the Activity binding goes to the correct type that Dagger knows about.

Note that the @Binds @IntoMap @ActivityKey(...) binding in DemoActivityModule still needs to go onto the ApplicationComponent, so the ApplicationComponent can determine which subcomponent to create from the class of the Activity being injected. You specifically want the new DemoActivitySubcomponentModule to go onto DemoActivitySubcomponent so that it makes the Activity-to-DemoActivity in a place where DemoActivity2Subcomponent can't see it.

As a side note, the problem you're seeing is the conflict between the two bindings to Activity, which happen in the same component. It's not quite right to say the same scope, because (though you might choose to add a scope annotation like @ActivityScope to each subcomponent) there is no scope annotation that would help you here. The seedInstance will apply only within each currently-unscoped subcomponent, which will combine with bindings in the ancestor components as well as the subcomponent-specific modules.

Recommend

  • Do I need to clean user input for DB::query calls in laravel?
  • Can't remove inline event handler in chrome
  • How to test method of JavaFX controller?
  • How to “remove”/“change” some require(…) calls when using browserify?
  • Set text in TextView in custom dialog
  • Retrofit 2 error: NetworkOnMainThreadException
  • RxJava,Retrofit Error :Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
  • How to add plugin dependencies to pom.xml
  • Can I customize a Jackson ObjectMapper by adding a module?
  • Trying to get all column names in a table
  • How to set the navigation bar to the top in Table View?
  • UIPickerView without IB?
  • Cassandra NoClassDefFoundError: com/google/common/util/concurrent/AsyncFunction
  • SqlCommand back up Database
  • Javascript simulate pressing enter in input box
  • How reduce the height of an mschart by breaking up the y-axis
  • How to add date and time under each post in guestbook in google app engine
  • SSO with signing and signature validation doesn't work
  • How to show dropdown in excel using jrxml (jasper api)?
  • Importing jscolor library in angular 2
  • Release, debug version and Authorization Google?
  • Websockets service method fails during R startup
  • Alternatives to the OPTIONAL fallback SPARQL pattern?
  • How to get next/previous record number?
  • Apache 2.4 - remove | delete | uninstall
  • Proper way to use connect-multiparty with express.js?
  • Angular 2 constructor injection vs direct access
  • Trying to get generic when generic is not available
  • embed rChart in Markdown
  • Change div Background jquery
  • Qt: Run a script BEFORE make
  • How to get Windows thread pool to call class member function?
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • reshape alternating columns in less time and using less memory
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • How to Embed XSL into XML
  • UserPrincipal.Current returns apppool on IIS
  • Conditional In-Line CSS for IE and Others?
  • java string with new operator and a literal