假设我有以下类:
class Foo {}
class Bar {
Foo mFoo = new Foo();
}
class MyActivity extends AppCompatActivity {
Bar mBar = new Bar();
@Override
protected void onCreate (Bundle savedInstance) {
super(savedInstance);
}
}
从上面的代码可以看出,MyActivity依赖于Bar和Bar取决于Foo。使用Dagger2实现依赖注入的正确方法是什么?
到目前为止,我处理这种类型操作系统的方式是:
配置
@Singleton
@Component(
modules = {
MainModule.class,
})
public interface MainComponent {
void inject(MyActivity myActivity);
void inject(Bar bar);
}
@Module
class MainModule {
@Provides
@Singleton
Foo provideFoo() {
return new Foo();
}
@Provides
@Singleton
Bar provideBar() {
return new Bar();
}
}
注塑
class Bar {
@Inject Foo mFoo;
Bar() {inject(this);}
}
class MyActivity extends AppCompatActivity {
@Inject Bar mBar;
@Override
protected void onCreate (Bundle savedInstance) {
super(savedInstance);
inject(this);
}
}
问题是,根据this回答,它不应该像那样工作,Bar
不应该调用inject
并且Foo
作为参数传递。但是,如果我在项目的其他部分需要Foo
的单例实例,该怎么办?我应该如何使用Dagger2来实现给定的场景?
答案 0 :(得分:1)
如果将Bar
的构造函数的签名更改为以下内容,则应达到所需的效果(构造函数注入)。
class Bar {
Foo foo;
@Inject
Bar(Foo foo) {
this.foo = foo;
}
}
然后你只需要在提供者中指定Bar
的依赖关系,方法是将其写为方法参数:
@Provides Bar provideBar(Foo foo)
由于已知Foo
和Bar
掠过@Provide
方法,因此dagger会自动创建Foo
的实例以获取Bar
的实例。像这样的构造函数注入将具有使代码易于单元测试的附加优势。在您的测试中,您可以使用模拟Foo
替换真实Foo
,并在Foo
上测试Bar
的互动。
仅当您无权访问构造函数时(例如,在Android Activity
和Service
中),属性注入才是最佳选择。对于其他依赖项,最好使用构造函数注入。
答案 1 :(得分:1)
您不需要使用模块来提供普通类。您可以直接注释类。要始终将Foo作为单例提供,您可以对类本身进行注释。
@Singleton
@Component
public interface MainComponent {
void inject(MyActivity myActivity);
}
@Singleton
public class Foo {
@Inject
public Foo(){}
}
@Singleton
public class Bar {
private final Foo foo;
@Inject
public Bar(final Foo foo){
this.foo = foo;
}
}
当您需要构建/配置实例或提供接口实现时,需要模块。例如:
@Module
class MainModule {
@Singleton
@Provides
Gson gson() {
return new GsonBuilder.create();
}
@Singleton
@Provides
IBar bar(Bar bar){
return bar;
}
}
// You can also provide an interface with the @Binds attribute instead
// of using the traditional @Provides annotation
@Module
abstract class MainBindsModule {
@Singleton
@Binds
abstract IBar bar(Bar bar);
}