我开始在我正在开发的应用程序中使用Dagger 2,但我对Dagger 2的工作方式有一些疑问.
我得到了@Provides方法和@Inject注释背后的所有逻辑来初始化你的依赖关系,但@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类,这取决于上下文,我想在我的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)时,它"告诉"匕首所有@Inject注释都是我的类的依赖项,然后它搜索我的项目以获取与该类型匹配的@Inject注释构造函数?
我认为关于Dagger 2的一个好处是模块文件可以用作我的依赖关系三的"文档".但是如果只是在我控制的所有构造函数中添加@Inject,将来不会有点混乱,因为你不知道实际上取决于什么?(我的意思是,你知道什么取决于什么,你只需要浏览很多文件才能真正找到答案)
在构造函数中使用@Inject注释或何时在Modules文件中添加@Provides方法时,是否有任何最佳实践?我在构造函数中使用@Inject得到了我不需要在我的Module文件中更改构造函数定义,但是有任何缺点吗?
谢谢.
1> David Medenj..:
当我调用injectBaseActivity(this)时,它"告诉"匕首所有@Inject注释都是我的类的依赖项,然后它在我的项目中搜索匹配该类型的@Inject注释构造函数?
究竟.但是当你打电话时却没有完成injectBaseActivity
,但这一切都发生在编译期间.这是注释处理的一种方式(另一种方法是在运行时使用反射).
在构建项目时,您在build.gradle文件中包含的(作为依赖项)的dagger-annotation-processor将通过注释注释的所有字段,类等的列表进行调用,@Inject
并使用它构建依赖关系图.然后它解析图形,生成源代码,提供图形上项目的所有依赖项.
injectBaseActivity
只执行之前生成的代码,并将所有依赖项分配给您的对象.它是正确的源代码,您可以阅读和调试.
这是一个简单的编译步骤 - 性能和验证.(例如,如果您有一些依赖循环,则会出现编译错误)
dagger如何知道我的AuthControllers是BaseActivity的依赖?
@Inject
AuthController authController;
通过注释场@Inject
匕首知道你想要一个AuthController
.到现在为止还挺好.现在,dagger将寻找一些方法来提供控制器,在组件内查找它,组件依赖项和组件模块.它还将查看该类是否可以自己提供,因为它知道它的构造函数.
如果您不在任何模块中包含它,匕首如何知道对象构造函数?
@Inject
public AuthController(Context context) { /**/ }
通过使用注入来注释构造函数,您还告诉dagger有一个被调用的类AuthController
,您需要一个上下文来实例化它.它与将其添加到模块基本相同.
@Provides
如果您没有源代码只是将@Inject
注释添加到构造函数,或者对象需要进一步初始化,则应使用模块方法.或者在你的情况下......
[...]模块文件可以用作我的依赖树的"文档"[...]
是的,当然你可以这样做.但随着项目的增长,您将不得不维护许多不必要的代码,因为在构造函数上使用简单的注释也可以完成相同的操作.
在构造函数中使用@Inject注释或何时在Modules文件中添加@Provides方法时,是否有任何最佳实践?
如果要为不同的上下文提供不同的版本(例如,以两种不同的方式实现接口),还有一个@Binds
注释告诉dagger您希望将哪个类作为实现提供.
除此之外,我相信你应该尽可能使用构造函数注入.如果发生了变化,您不必触及代码的任何其他部分,只需要编写的代码就少,因此可以包含错误的地方更少.
Dagger也可以并且通过了解更多来优化很多,如果你实现不必要的代码,它将不得不处理你引入的开销
当然,最终完全取决于您认为最好的.毕竟,你必须使用你的代码;)
@saiedVanguard有可能:`class A @Inject constructor(...)`