6

使用 Dagger 时,哪些方法允许在也通过注入实例化的对象上自由/轻松地实例化 @Inject 字段。

例如,下面的代码会将 Bar 类型的对象注入给定的 Foo 对象。它将以显示的两种方式之一执行此操作。但是,每个 Bar 对象的 Sly 字段与该行为不匹配。

public class Foo {
  @Inject Bar bar;

  public String getValue() {
    return "Foo's bar value: " + bar.getValue();
  }
}

public class Bar {
  @Inject Sly sly;

  public String getValue() {
    return "Bar's sly value: " + sly.getValue();
  }
}

狡猾

public class Sly {
  public String getValue() {
    return "Hey!";
  }
}

模块

@Module(
    injects = {
        Foo.class,
        Bar.class
    }
)
public class ExampleTestModule {
  @Provides
  Bar provideBar() {
    return new Bar();
  }

  @Provides
  Sly provideSly() {
    return new Sly();
  }
}

测试

public void testWorksWithInject() {
  Foo foo = new Foo();
  ObjectGraph.create(new ExampleTestModule()).inject(foo);
  assertEquals("...", foo.getValue()); // NullPointerException
}

public void testWorksWithGet() {
  Foo foo = ObjectGraph.create(new ExampleTestModule()).get(Foo.class);
  assertEquals("...", foo.getValue()); // NullPointerException
}

在任何一种情况下,Bar 的 Sly 都没有被实例化/@Injected。当然,Dagger 允许构造函数注入,从而解决了这个问题。我想知道是否有其他方法可以将这些类放入构造函数的参数列表中。什么适合你?

4

1 回答 1

9

所以这里的问题是 Bar 上面有 @Inject Sly,但是你在 @Provides 方法中提供了 Bar 。@Provides 方法会覆盖默认的实例化行为,因此您要告诉 Dagger 实例化“new Bar()”并将其作为 Bar 规定的履行返回。

您可以做的最简单的事情就是删除 provideBar() 方法,因为它是不必要的。如果具体类型具有@Inject 构造函数或@Inject 字段,则Dagger 将注入其依赖项并创建它,除非它具有不可访问的构造函数或没有@Inject 的参数化构造函数。但是您上面的类 Bar{} 的情况完全适合隐式绑定,而不使用 @Provides 方法。

如果您出于某种原因需要更改该默认行为,您仍然可以在 @Provides 方法中创建它,但您必须手动传入注入的值。但是,@Provides 方法本身可以通过向 @Provides 方法本身添加参数来注入。所以你可以这样做。

@Provides
Bar provideBar(Sly sly) {
  Bar bar = new Bar();
  bar.sly = sly;
  return bar;
}

@Provides 方法负责正确配置实例,包括新建、分配、任何初始化逻辑等。

但是,鉴于您上面的示例,简单的解决方案是简单地从您的模块中删除 provideBar() 并让 Dagger 自动初始化 Bar。

Dagger 2 似乎有一些不同的替代方案用于嵌套注入:请求一个组件,MembersInjector,或者给 Bar 一个 @Inject 带注释的构造函数。

如果 Bar 有一个 @Inject 带注释的构造函数,那么您可以实现完全的不变性:

class Bar {
  private final Sly sly;

  @Inject
  public Bar(Sly sly) {
    this.sly = sly;
  }
}

当您仅部分注入成员时,另一种选择是使用带有 MembersInjector 或组件(MembersTestComponent?)的 @Provides 方法作为方法参数:

@Provides
Bar provideBar(MembersInjector<Bar> injector) {
  Bar bar = new Bar();
  injector.inject(bar);
  return bar;
}

不幸的是,提供 MembersTestComponent 参数会将 Module 耦合回您的 Component 并降低解决方案的凝聚力。如果 Bar 包含由组件提供的作用域值(例如,Jake Wharton 的 Devoxx 2014 演讲中的 Tweeter 中的用户),则提供 MembersInjector 尤其有用。

于 2014-02-11T20:45:55.963 回答