我是Dagger(Android上的2.16版本(的新手,根据我到目前为止的阅读,我知道对于一个组件,应该有一个提供程序(@Provides
或@Binds
(封装在一个模块(@Module
(。通过很多示例,我看到代码包含一些在任何模块中都没有提供的对象,也没有使用 new 实例化它们。
我的理解是,为了访问模块中的依赖项,消费者类需要在组件图中注入自身(组件通常提供注入类的方法(。代码示例也没有这样做。
这里有一些代码展示了我的两个问题。RecipePresenter没有在任何模块中提供,但RecipeActivity仍在使用它。
我能想到的一个可能的解释是,@Inject
,除了请求依赖项外,还会将请求类(链接代码中的RecipePresenter
(添加/注入到组件图中。但是假设有多个组件/子组件,使用构造函数@Inject
类附加到哪个组件?如果我的理解是正确的,为什么活动和片段必须在组件中手动注入自己 - 如果它们声明了一个用@Inject
注释的变量,它们不应该自动注入吗?
RecipePresenter有一个@Inject
注释的构造函数,它允许它被提供。RecipeActivity 中recipePresenter
字段中的@Inject
注释没有帮助,只有@Inject
注释的构造函数。
class RecipePresenter @Inject constructor(
private val useCase: RecipeUseCase,
private val res: StringRetriever) :
RecipeUseCase.Callback {
来自dagger用户指南:
使用
@Inject
批注 Dagger 用于创建类实例的构造函数。当请求新实例时,Dagger 将获取所需的参数值并调用此构造函数。
如果具有@Inject
-annotated 构造函数的类也具有定义的作用域,则绑定将仅影响具有相同作用域注释的组件:例如,无法从@Singleton
组件访问@ActivityScope
类。如果类没有定义作用域,则绑定可以出现在需要它的任何和所有组件上,这很好:实现始终相同,由构造函数本身定义。
@Inject
根据其注释的内容具有不同的含义:
- 使用
@Inject
注释字段时,它指示 DI 系统在注入该对象时应根据 DI 系统中的值设置该字段。 - 使用
@Inject
注释方法时,它指示 DI 系统在注入该对象时应使用基于 DI 系统中的值的参数调用该方法。 - 当您使用
@Inject
注释构造函数时,它表示允许 DI 系统调用该构造函数以创建该对象(这会触发上面的字段和方法注入(。从这个意义上说,它确实像一个内置的提供程序。
特别是在 Dagger 中,@Provides
方法优先于@Inject
构造函数(如果它们都存在于同一个类中(,并且与 JSR-330 规范不同,Dagger 需要@Inject
注释构造函数,即使不存在其他构造函数。来自dagger用户指南:
如果您的类有
@Inject
注释字段但没有@Inject
注释构造函数,则 Dagger 将根据请求注入这些字段,但不会创建新实例。添加带有@Inject
注释的无参数构造函数,以指示 Dagger 也可以创建实例。缺少
@Inject
注释的类不能由 Dagger 构造。
最后,回答你关于为什么活动和片段需要注入自身的问题:Android 可以在没有 Dagger 帮助或参与的情况下反射性地创建活动/片段/视图对象。这意味着不会触发上述字段和方法注入,直到在组件上调用成员注入方法,该方法指示 Dagger 填充这些字段并调用这些方法。因此,你不应该在 Android 中的 Application、Activity、Service、Fragment、View、ContentProvider 和 BroadcastReceiver 子类上看到@Inject
注释的构造函数:Android 会忽略@Inject
注释,所以你最好自己控制注入,手动或通过 dagger.android。