我开始在正在开发的应用程序中使用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();
}
}
现在我的问题是,匕首怎么知道我的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的一件好事是,模块文件可用作我的依赖项3的“文档”。但是,如果仅在我控制的所有构造函数中添加@Inject,将来它不会变得有些混乱,因为您不知道实际上取决于什么?(我的意思是,您知道什么取决于什么,您只需要浏览很多文件即可真正找出来)
在构造函数中使用@Inject批注或在Modules文件中添加@Provides方法时,是否有最佳实践?我在构造函数中使用@Inject可以得到这些信息,而无需在我的Module文件中更改构造函数定义,但是有什么缺点吗?
谢谢。
当我调用injectBaseActivity(this)时,它“告诉”匕首说所有@Inject注释都是我的类的依赖项,然后它在我的项目中搜索与该类型匹配的@Inject带注释的构造函数?
究竟。但这在您调用时还没有完成injectBaseActivity
,而是全部在编译时发生。这是 注释处理的 一种方式(另一种在运行时使用反射)。
在构建项目时,您在build.gradle文件中包含(作为依赖项)的dagger-annotation-
processor将被调用,并带有注释所@Inject
注释的所有字段,类等的列表,并以此构建依赖关系图。然后,它解析该图,生成提供该图上项目所有依赖项的源代码。
injectBaseActivity
只需执行之前生成的代码,并将所有依赖项分配给您的对象。它是正确的源代码,您可以阅读和调试。
简而言之,这是编译步骤的原因是性能和验证。(例如,如果您有一些依赖周期,则会出现编译错误)
匕首如何知道我的AuthControllers是BaseActivity的依赖项?
@Inject
AuthController authController;
通过注释字段@Inject
匕首,您知道您想要一个AuthController
。到目前为止,一切都很好。现在,匕首将寻找一些提供控制器的方法,在组件,组件依赖项和组件模块中寻找它。它还将查看是否可以单独提供该类,因为它
知道 其构造函数。
如果您不将dagger包含在任何模块中,它将如何得知对象构造函数?
@Inject
public AuthController(Context context) { /**/ }
通过使用inject注释构造函数,您还告诉dagger有一个名为的类,AuthController
并且需要实例化它。它与将其添加到模块中基本相同。
@Provides
如果您没有将@Inject
批注添加到构造函数的源代码,或者对象需要进一步的初始化,则应使用模块方法。或者就你而言…
[…]模块文件可用作我的依赖项树的“文档” […]
是的,您当然可以这样做。但是随着项目的增长,您将必须维护 许多 不必要的代码,因为在构造函数上使用简单的注释也可以完成相同的操作。
在构造函数中使用@Inject批注或在Modules文件中添加@Provides方法时,是否有最佳实践?
如果要为不同的上下文提供不同的版本(例如,以2种不同的方式实现接口),则还可以使用@Binds
注释来告诉dagger您希望提供哪个类作为实现。
除此之外,我相信您应该尽可能使用构造函数注入。如果有什么变化,您不必接触代码的任何其他部分,并且只需编写较少的代码,因此可以减少包含错误的位置。
此外,Dagger可以而且确实可以通过了解更多信息来进行很多优化,并且,如果您实现了不必要的代码,则它必须与您引入的开销一起工作。
当然,最终取决于您的最佳想法。毕竟, 您 必须使用 您的 代码;)
我有很多Android ViewModel类,它们往往有很多依赖项(大多数是Room中的DAO,每个SQLite表一个)。有些依赖项超过10个。 这很好,但Inject构造函数充满了参数,并且只包含样板代码,用于从构造函数参数设置注入的成员。 我想切换到“常规”注入成员,使用注释单独标识,就像其他(哑)类一样。 这对于与Android相关的类(尽管ViewModel被宣传为非Android依赖,例
我刚开始使用Dagger并尝试使用dagger2进行DI,但看起来它给我的活动注入了一个空演示器。下面是我的代码。 公共类TasksActivity扩展AppCompatActivity{
我把下面的内容看做是构造函数和setter注入的区别之一。有人能用一些简单的例子解释一下下面的区别吗,我对术语完全功能对象和不完全对象有点困惑。 -
请帮助理解在哪种情况下我应该使用构造函数注入和设置器注入。请帮我举个合适的例子。 先谢谢你。
主要内容:输出注入是将依赖注入对象的过程。构造函数注入很常见。在这个过程中,依赖被作为参数注入到构造函数中。请参阅下面的示例。 创建一个名为 GuiceTester 的 Java 类。 GuiceTester.java 输出 编译并运行该文件,您将看到以下输出。
注入是将依赖注入对象的过程。 构造函数注入很常见。 在此过程中,依赖项作为参数注入构造函数。 请参阅下面的示例。 创建一个名为GuiceTester的java类。 GuiceTester.java import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Inj