如果找不到@Named,则使用dagger进行默认实现

时间:2018-05-23 08:34:39

标签: java android dagger-2

我面临的问题是我有一个基类和多个子类。为了解析特定的子类,我在Dagger 2中使用@Named注释。我想要实现的是如果我使用@Named(“Child3”)注入并且没有提供@Named(“Child3”)那么我应该默认情况下获取Base类的实例。

public class BaseClass {

public void haveFun(){
    System.out.print("Having fun base");
}

}

public class Child1 extends BaseClass {
@Override
public void haveFun() {
    System.out.print("Having fun Child1");
}
}

public class Child2 extends BaseClass {
@Override
public void haveFun() {
    System.out.print("Having fun Child2");
 }
}

现在在模块中我提供了这样的对象:

 @Provides
@Named("Child1")
static BaseClass provideChild1(){
    return new Child1();
}

@Provides
@Named("Child2")
static BaseClass provideChild2(){
    return new Child2();
}


@Provides
static BaseClass provideBaseClass(){
    return new BaseClass();
}

现在,在我的活动中,我正在注射:

public class ReceiptActivity extends AppCompatActivity {

@Inject @Named("Child1") BaseClass child1;
@Inject @Named("Child2") BaseClass child2;
@Inject @Named("Child3") BaseClass child3;

由于没有提供@Named(“Child3”),因此存在编译时错误,但我想要的是如果@Named(“Child3”)不在那里我应该得到BaseClass实例。 我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:1)

不幸的是,限定绑定(使用限定符注释的绑定,如@Named)实际上没有回退或默认值。每个绑定都是不同的,并且不认为不同的绑定是相关的。这使得很难像你要求的那样编写回退逻辑。

这也是有道理的:尽管共享基类型,@Named("Porsche") Engine@Named("Lawnmower") Engine永远不会真正替代彼此。它们是完全不同的依赖项,如果你错过了@Named("Porsche") Engine,Dagger会遵循它应该在编译时失败的策略,而不是为了找不匹配或不合格的引擎。 / p>

相比之下,您可以绑定地图或使用Multibindings来表示您正在寻找的可替代性或灵活性。你不是注入绑定本身,而是注入一个Map,或者注入一个封装地图的Factory并为你拉出正确的绑定。

// This uses Multibindings, but you could manually create a Map instead.

@Binds @IntoMap @StringKey("Child1")
abstract BaseClass provideChild1(Child1 child1);

@Binds @IntoMap @StringKey("Child2")
abstract BaseClass provideChild2(Child2 child2);

// Then in your consumer...

@Inject Map<String, BaseClass> mapOfBaseClasses;
@Inject BaseClass baseClass;

// Or make an injectable Factory:

public class YourClassFactory {
  private final Map<String, Provider<BaseClass>> baseClassMap;
  private final Provider<BaseClass> baseClassProvider;

  @Inject public YourClassFactory(/* ... */) { /* set fields */ }

  public BaseClass get(String key) { /* write fallback logic here */ }
}

如果您有可能存在或不存在的特定绑定,您还可以使用@BindsOptionalOf指示在编译时允许绑定丢失,然后您可以在运行时检测它。

@BindsOptionalOf @Named("Child3")
abstract BaseClass provideOptionalOfChild3();

// Then in your consumer:

private final BaseClass baseClass;

@Inject public YourConsumer(
    @Named("Child3") Optional<BaseClass> optionalChild3,
    Provider<BaseClass> defaultBaseClass) {
  baseClass =
      optionalChild3.isPresent()
      ? optionalChild3.get()
      : defaultBaseClass.get();
}