多个具有相同返回类但键不同的@Binds

时间:2017-03-29 02:54:43

标签: android dagger-2

以下所有内容均与dagger 2.10和dagger.android包一起使用。

假设我有一门课,我想参加多项活动。

public class DemoSharedClass {
  Activity activity;

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

然后,使用最新的Dagger API,我的类被定义为

public class DemoActivity extends DaggerActivity {
  @Inject DemoSharedClass demoSharedClass;

  // ...
}

public class Demo2Activity extends DaggerActivity {
  @Inject DemoSharedClass demoSharedClass;

  // ...
}

每个活动都将其模块和子组件定义为(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> {}
}

最后,app组件定义为

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

现在,我在构建项目时遇到了这个错误:

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)

我收到错误,我认为这是因为它们属于相同的范围,即应用程序组件。

我考虑过为两个DemoSubcomponents创建一个公共模块,它看起来像下面这样,但有类似的错误。

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

问题:我该怎么做?

1 个答案:

答案 0 :(得分:5)

您需要在每个子组件上单独绑定:

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

由于AndroidInjector.Builder中的@BindsInstance Builder seedInstance(DemoActivity),Dagger从AndroidInjector.Builder.create()调用DispatchingAndroidInjector,Dagger确实知道如何至少提供DemoActivity实例。但是,DemoActivity和Activity(或Context)之间没有内置绑定,因此必须在子组件而不是组件上进行绑定。通过将具有该绑定的模块放在适当的@Subcomponent上,可以确保在每个相应的子组件中Activity绑定转到Dagger知道的正确类型。

请注意,DemoActivityModule中的@Binds @IntoMap @ActivityKey(...)绑定仍需要转到ApplicationComponent,因此ApplicationComponent可以从正在注入的Activity类中确定要创建的子组件。您特别希望新的DemoActivitySubcomponentModule转到DemoActivitySubcomponent,以便在DemoActivity2Subcomponent无法看到它的地方生成Activity-to-DemoActivity。

作为旁注,您看到的问题是Activity的两个绑定之间的冲突,它发生在同一个组件中。说同一个范围是不对的,因为(尽管您可能会选择将@ActivityScope等范围注释添加到每个子组件中),但没有范围注释可以帮助您。 seedInstance仅适用于每个当前未扩展的子组件,它将与祖先组件中的绑定以及特定于子组件的模块结合使用。