匕首不是魔法。它不会神奇地将对象插入到您想要的任何地方,除非您告诉它这样做。
public class MainPresenterImpl implements MainViewPresenter {
// ... other fields ...
@Inject
ListingInteractor interactor;
public MainPresenterImpl(MainActivity activity) {
this.context = activity;
this.mainView = activity;
}
}
对于 Dagger 来说,这……没什么。您标记了一些字段(ListingInteractor
)用于字段注入,但除非您手动调用组件来注入对象,否则什么都不会发生。字段注入应该保留给无法向构造函数添加参数的活动和片段,而不是一般的类。
@Provides
@Singleton
MainViewPresenter providesMainPresenter(){
return new MainPresenterImpl(activity);
}
而不是让 Dagger 创建MainPresenterImpl
对于您来说,您可以拨打new MainPresenterImpl()
你自己,只传递 Activity 。由于没有电话MainPresenterImpl.interactor
, 这将是null
。您没有使用字段注入,您自己调用构造函数并且没有分配字段。
在模块中手动创建对象应该保留给需要进一步设置的对象,例如Retrofit
or OkHttp
和他们的建设者。
如果您希望设置字段,您可以使用字段注入并向组件注册您的对象(那些inject(FieldInjectableClass clazz)
方法)并撒上component.inject(myObject)
在整个代码中,这将是一个非常糟糕的主意,因为您最终会编写大量不需要的样板文件。
更合理的方法是将依赖项移至它们所属的构造函数中。
public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }
如果您依赖于另一个类,为什么不这样声明它呢?但这仍然留下了您自己创建对象的样板,而不是让 Dagger 完成它的工作。
这就是为什么你应该使用构造函数注入。顾名思义,它是关于构造函数的。只需添加@Inject
注解:
@Inject // marked for constructor injection!
public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }
现在 Dagger 知道了你的类的这个入口点并可以创建它.
要让 dagger 处理事情,你可以添加@Singleton
范围到类本身(注释类,而不是构造函数),然后删除@Provides
方法(不需要在模块中为不需要进一步设置的对象提供方法),但由于您将实现绑定到接口,您仍然需要指定要绑定到接口的类。
@Provides
@Singleton
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation){
return implementation;
}
由于 Dagger 可以创建MainPresenterImpl
通过构造函数注入,您可以返回接口的实现,并且在构造函数签名发生变化时无需更新任何代码,因为 Dagger 只会相应地调整类实例化。
这就是如何使用构造函数注入并将实现绑定到接口。如前所述,我强烈建议您阅读基础知识。确保您了解 Dagger 的作用及其工作原理。请务必了解字段注入和构造函数注入之间的区别,或者何时使用模块。
您现在投入学习 Dagger 的时间将意味着以后的调试和错误会少得多。
如果您的模块是抽象的或接口,您还可以使用@Binds
方法,其中 Dagger 将只生成上面的样板代码。
@Binds
@Singleton
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation);