Dagger 2 注入构造函数
Dagger 2 Injecting Constructors
我开始在我正在开发的应用程序中使用 Dagger 2,但我对 Dagger 2 的工作原理有一些疑问。
我了解了 @Provides 方法和用于初始化依赖项的 @Inject 注释背后的所有逻辑,但是 class 构造函数的 @Inject 注释让我心烦意乱。
例如:
在我的应用程序中,我定义了一个模块 ContextModule,用于检索我的应用程序的上下文:
ContextModule.java
@Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
@Provides
public Context context() {
return this.context;
}
}
这个模块被我的 BaseActivityComponent 使用:
BaseActivityComponent.java
@BaseActivityScope
@Component(modules = ContextModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
}
到目前为止一切顺利..然后我有一个 AuthController class,这取决于上下文,我想将它注入我的 BaseActivity。所以在我的 AuthControllers.class 中我有类似的东西:
public class AuthController {
private Context context;
@Inject
public AuthController(Context context) {
this.context = context;
}
public void auth() {
// DO STUFF WITH CONTEXT
}
}
然后我将它注入到我的 BaseActivity 中,例如:
public class BaseActivity extends AppCompatActivity {
@Inject
AuthController authController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseActivityComponent component = DaggerBaseActivityComponent.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseActivity(this);
authController.auth();
}
}
现在我的问题是,dagger 如何知道我的 AuthControllers 是 BaseActivity 的依赖项?只需声明
@Inject
AuthController authController;
这就像我创建一个 ControllerModule 一样:
@Module(includes = ContextModule.class)
public class ControllerModule {
@Provides
AuthController authController(Context context) {
return new AuthController(context);
}
}
然后在我的 BaseActivityComponent 中添加我的 AuthController getter 并将我的依赖模块更改为 ControllersModule:
@BaseActivityScope
@Component(modules = ControllersModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
AuthController getAuthController();
}
当我调用 injectBaseActivity(this) 时,它 "tells" 怀疑所有 @Inject 注释都是我的 class 的依赖项,然后它会在我的项目中搜索与该类型匹配的 @Inject 注释构造函数?
我认为 Dagger 2 的一个好处是模块文件可以用作我的依赖项 3 的 "documentation"。但是,如果只是在我控制的所有构造函数中添加 @Inject,将来会不会有点混乱,因为您不知道什么实际上取决于什么? (我的意思是,你知道什么取决于什么,你只需要浏览大量文件才能真正找出答案)
在构造函数中使用@Inject 注释或在模块文件中添加@Provides 方法时,是否有任何最佳实践?
我知道在构造函数中使用 @Inject 我不需要更改我的模块文件中的构造函数定义,但是有什么缺点吗?
谢谢。
When I call injectBaseActivity(this) it "tells" dagger that all @Inject annotations are dependencies of my class, and then it searches my project for @Inject annotated constructors that matches that type?
没错。但是当你调用 injectBaseActivity
时它并没有完成,但这一切都发生在编译期间。这是注释处理的一种方式(另一种在运行时使用反射)。
当您构建项目时,您在 build.gradle 文件中包含(作为依赖项)的 dagger-annotation-processor 将被调用,其中包含所有字段的列表,classes 等注释通过 @Inject
注释并用它构建一个依赖图。然后解析图表,生成源代码,为图表上的项目提供所有依赖关系。
injectBaseActivity
只是执行之前生成的代码,并将所有依赖项分配给您的对象。这是正确的源代码,您可以阅读和调试。
这是一个编译步骤的原因——简而言之——是为了性能和验证。 (例如,如果你有一些依赖循环,你会得到一个编译错误)
how does dagger knows that my AuthControllers is a dependency for BaseActivity?
@Inject
AuthController authController;
通过注释字段 @Inject
,dagger 知道您想要一个 AuthController
。到目前为止,一切都很好。现在 dagger 将寻找一些方法来提供控制器,在组件、组件依赖项和组件模块中寻找它。它还会查看 class 是否可以自己提供,因为它 知道 其构造函数。
如果您不将它包含在任何模块中,dagger 如何知道对象构造函数?
@Inject
public AuthController(Context context) { /**/ }
通过使用 inject 注释构造函数,您还告诉 dagger 有一个名为 AuthController
的 class,您需要一个上下文来实例化它。它与将它添加到您的模块基本相同。
如果您没有源代码只能将 @Inject
注释添加到构造函数,或者如果对象需要进一步初始化,则应使用模块 @Provides
方法。或者在你的情况下......
[...]the Module files could be used as a "documentation" of my dependencies tree [...]
是的,你当然可以这样做。但是随着项目的增长,您将不得不维护 大量 不必要的代码,因为同样可以通过构造函数上的简单注释来完成。
Is there any best practices for when using @Inject annotations in constructors or when to add the @Provides method in Modules files?
如果您想为不同的上下文提供不同的版本(例如,以两种不同的方式实现接口),还有 @Binds
注释告诉 dagger 您希望提供哪个 class 作为实施。
除此之外,我相信您应该尽可能使用构造函数注入。如果有什么变化,您不必触及代码的任何其他部分,而且您编写的代码会更少,因此您可能包含错误的地方也会更少。
Dagger 也可以并且确实通过了解更多来进行很多优化,如果您实现不必要的代码,它将不得不使用您引入的开销
当然最后还是看你觉得怎样最好。毕竟 你 必须使用 你的 代码 ;)
我开始在我正在开发的应用程序中使用 Dagger 2,但我对 Dagger 2 的工作原理有一些疑问。
我了解了 @Provides 方法和用于初始化依赖项的 @Inject 注释背后的所有逻辑,但是 class 构造函数的 @Inject 注释让我心烦意乱。
例如:
在我的应用程序中,我定义了一个模块 ContextModule,用于检索我的应用程序的上下文:
ContextModule.java
@Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
@Provides
public Context context() {
return this.context;
}
}
这个模块被我的 BaseActivityComponent 使用:
BaseActivityComponent.java
@BaseActivityScope
@Component(modules = ContextModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
}
到目前为止一切顺利..然后我有一个 AuthController class,这取决于上下文,我想将它注入我的 BaseActivity。所以在我的 AuthControllers.class 中我有类似的东西:
public class AuthController {
private Context context;
@Inject
public AuthController(Context context) {
this.context = context;
}
public void auth() {
// DO STUFF WITH CONTEXT
}
}
然后我将它注入到我的 BaseActivity 中,例如:
public class BaseActivity extends AppCompatActivity {
@Inject
AuthController authController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseActivityComponent component = DaggerBaseActivityComponent.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseActivity(this);
authController.auth();
}
}
现在我的问题是,dagger 如何知道我的 AuthControllers 是 BaseActivity 的依赖项?只需声明
@Inject
AuthController authController;
这就像我创建一个 ControllerModule 一样:
@Module(includes = ContextModule.class)
public class ControllerModule {
@Provides
AuthController authController(Context context) {
return new AuthController(context);
}
}
然后在我的 BaseActivityComponent 中添加我的 AuthController getter 并将我的依赖模块更改为 ControllersModule:
@BaseActivityScope
@Component(modules = ControllersModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
AuthController getAuthController();
}
当我调用 injectBaseActivity(this) 时,它 "tells" 怀疑所有 @Inject 注释都是我的 class 的依赖项,然后它会在我的项目中搜索与该类型匹配的 @Inject 注释构造函数?
我认为 Dagger 2 的一个好处是模块文件可以用作我的依赖项 3 的 "documentation"。但是,如果只是在我控制的所有构造函数中添加 @Inject,将来会不会有点混乱,因为您不知道什么实际上取决于什么? (我的意思是,你知道什么取决于什么,你只需要浏览大量文件才能真正找出答案)
在构造函数中使用@Inject 注释或在模块文件中添加@Provides 方法时,是否有任何最佳实践? 我知道在构造函数中使用 @Inject 我不需要更改我的模块文件中的构造函数定义,但是有什么缺点吗?
谢谢。
When I call injectBaseActivity(this) it "tells" dagger that all @Inject annotations are dependencies of my class, and then it searches my project for @Inject annotated constructors that matches that type?
没错。但是当你调用 injectBaseActivity
时它并没有完成,但这一切都发生在编译期间。这是注释处理的一种方式(另一种在运行时使用反射)。
当您构建项目时,您在 build.gradle 文件中包含(作为依赖项)的 dagger-annotation-processor 将被调用,其中包含所有字段的列表,classes 等注释通过 @Inject
注释并用它构建一个依赖图。然后解析图表,生成源代码,为图表上的项目提供所有依赖关系。
injectBaseActivity
只是执行之前生成的代码,并将所有依赖项分配给您的对象。这是正确的源代码,您可以阅读和调试。
这是一个编译步骤的原因——简而言之——是为了性能和验证。 (例如,如果你有一些依赖循环,你会得到一个编译错误)
how does dagger knows that my AuthControllers is a dependency for BaseActivity?
@Inject
AuthController authController;
通过注释字段 @Inject
,dagger 知道您想要一个 AuthController
。到目前为止,一切都很好。现在 dagger 将寻找一些方法来提供控制器,在组件、组件依赖项和组件模块中寻找它。它还会查看 class 是否可以自己提供,因为它 知道 其构造函数。
如果您不将它包含在任何模块中,dagger 如何知道对象构造函数?
@Inject
public AuthController(Context context) { /**/ }
通过使用 inject 注释构造函数,您还告诉 dagger 有一个名为 AuthController
的 class,您需要一个上下文来实例化它。它与将它添加到您的模块基本相同。
如果您没有源代码只能将 @Inject
注释添加到构造函数,或者如果对象需要进一步初始化,则应使用模块 @Provides
方法。或者在你的情况下......
[...]the Module files could be used as a "documentation" of my dependencies tree [...]
是的,你当然可以这样做。但是随着项目的增长,您将不得不维护 大量 不必要的代码,因为同样可以通过构造函数上的简单注释来完成。
Is there any best practices for when using @Inject annotations in constructors or when to add the @Provides method in Modules files?
如果您想为不同的上下文提供不同的版本(例如,以两种不同的方式实现接口),还有 @Binds
注释告诉 dagger 您希望提供哪个 class 作为实施。
除此之外,我相信您应该尽可能使用构造函数注入。如果有什么变化,您不必触及代码的任何其他部分,而且您编写的代码会更少,因此您可能包含错误的地方也会更少。
Dagger 也可以并且确实通过了解更多来进行很多优化,如果您实现不必要的代码,它将不得不使用您引入的开销
当然最后还是看你觉得怎样最好。毕竟 你 必须使用 你的 代码 ;)