使用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's Sly都没有被实例化/ @Injected。当然,Dagger允许构造函数注入,这解决了问题。我想知道是否有替代方法将这些类塞入构造函数的参数列表中。什么对你有用?
答案 0 :(得分:9)
所以这里的问题是Bar上有@Inject Sly,但是你在@Provides方法中提供了Bar。 @Provides方法覆盖默认的实例化行为,因此您告诉Dagger实例化“new Bar()”并将其作为Bar的规定的实现返回。
您可以做的最简单的事情就是删除provideBar()方法,因为它是不必要的。如果具体类型具有@Inject构造函数或@Inject字段,则Dagger将注入其依赖项并创建它,除非它具有不可访问的构造函数或没有@Inject的参数化构造函数。但是上面的Bar {}类以上的情况完全适用于隐式绑定,而不使用@Provides方法。
如果由于某种原因需要更改默认行为,您仍然可以在@Provides方法中创建它,但必须手动传入注入的值。但是,@ Provide方法本身可以通过向@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或component(MembersTestComponent?)的@Provides方法作为方法参数:
@Provides
Bar provideBar(MembersInjector<Bar> injector) {
Bar bar = new Bar();
injector.inject(bar);
return bar;
}
不幸的是,提供MembersTestComponent参数会将模块耦合回组件并使解决方案不那么紧密。如果Bar包含Component提供的范围值(例如,在Jake Wharton的Devoxx 2014谈话中Tweeter内的用户),提供MembersInjector特别有用。