我注意到许多开发人员要做的一件事是创建一个从Application继承的类,然后通过依赖注入创建一个组件,该组件实际上包括组成其应用程序的所有模块。这是在onCreate方法中完成的。我觉得这很奇怪。为什么要将每个模块注入Application类并使其全局可用。毕竟,大多数模块(例如演示者)都绑定到单个活动,并且永远不会用于任何其他活动。那么,为什么不只在活动中创建一个组件,而只包含所需的那些模块,在活动中,这将是一个presenter类。
答案 0 :(得分:1)
我不确定是否同意以下前提:大多数应用程序在Application#onCreate中创建一个组件,但是我相信大多数应用程序还具有包含按活动,按碎片或按服务绑定的单独组件,并且这些组件/模块仅存在,并且仅在您使用有问题的特定活动/片段/服务时才进行类加载。
Dagger通过单独的组件管理对象生命周期("scope"),每个组件都可以具有自己的模块集。您使用一个或多个范围注释对组件进行注释,然后使用相同范围进行注释的任何绑定(或使用该范围注释和带有@Inject
注释的构造函数的任何类)将仅创建一次并存储在组件中。这与Dagger的默认行为相反,Dagger的默认行为是调用@Provides
方法或为每次调用组件方法或每个@Inject
注释字段创建一个新的对象实例。您可以控制何时创建组件实例,因此可以控制范围的语义:如果要创建名为@PerActivity
的范围注释,并为Android创建的每个Activity实例创建一个新的组件实例,那么您可以确保所有标记为@PerActivity
的绑定都将在该Activity的生存期内返回相同的实例。同样,您可以创建一个@UserScope
,每个用户都可以得到一个单独的组件实例。 JSR-330中唯一的标准化范围是@Singleton
,它应适用于整个应用程序。
但是,如果要混合作用域(如具有@PerActivity StatusBarPresenter)取决于@Singleton LoginService,该怎么办? Dagger要求您将它们保留在两个单独的组件中,以便StatusBarPresenter可以在@PerActivity ActivityComponent
中定义,而LoginService可以在@Singleton ApplicationComponent
中定义。您需要在此ActivityComponent和ApplicationComponent之间建立关系,可以通过具有依赖关系的组件或子组件来实现。
具有依赖性的组件将分别生成代码,并在dependencies
批注的@Component
属性中列出其依赖性。此时,您需要在其
@Singleton @Component(modules = {FooModule.class, BarModule.class})
interface ApplicationComponent {
Foo foo();
// Bar also exists, but is not listed. Let's say Foo uses it internally.
}
@PerActivity @Component(
modules = {BazModule.class},
dependencies = {ApplicationComponent.class})
interface ActivityComponent {
Baz baz();
}
ActivityComponent activityComponent =
DaggerActivityComponent.builder()
.applicationComponent(yourExistingApplicationComponent)
.build();
ActivityComponent拥有自己的代码生成步骤,并且可以与ApplicationComponent并行编译;但是,ActivityComponent只能访问依赖项Foo,而不能访问Bar。这是因为ActivityComponent列出了ApplicationComponent作为依赖项,并且ApplicationComponent没有列出Bar。因此,在ActivityComponent上定义的Baz可以自动注入Foo但不能注入Bar。实际上,如果Foo停止使用Bar,ApplicationComponent甚至可能根本不会生成用于创建Bar的代码。
相反,子组件是作为其父组件的一部分生成的,因此父组件充当工厂。
@Singleton @Component(modules = {FooModule.class, BarModule.class})
interface ApplicationComponent {
Foo foo();
// This is a subcomponent builder method, which can also return a
// @Subcomponent.Builder. More modern code uses the "subcomponents" attribute
// on the @Module annotation.
ActivityComponent createActivityComponent();
}
@PerActivity @Subcomponent(
modules = {BazModule.class},
dependencies = {ApplicationComponent.class})
interface ActivityComponent {
Baz baz();
}
ActivityComponent activityComponent =
yourExistingApplicationComponent.createActivityComponent();
// or, from somewhere that ApplicationComponent injects:
@Inject Provider<ActivityComponent> activityComponentProvider;
ActivityComponent activityComponent = activityComponentProvider.get();
对于子组件,ActivityComponent的实现与ApplicationComponent同时生成,这也意味着ApplicationComponent在生成代码时可以评估ActivityComponent的需求。因此,如果ApplicationComponent或ActivityComponent消耗了Bar实例,则创建Bar实例的代码将包含在ApplicationComponent中。但是,此构建步骤可能会变慢,因为Dagger将需要分析整个应用程序的依赖关系图。
所有这些都返回到Application#onCreate以及您所看到的内容:
dagger.android
和@ContributesAndroidInjector
,则说明您使用的子组件的顶部带有一些语法糖。请注意,@ContributesAndroidInjector
可以使用范围注释进行注释,并且可以使用modules
的列表,该列表将被传递到它生成的子组件。您对AndroidInjection.inject(this)
的调用将创建这些子组件实例之一,并根据需要对子组件及其模块进行类加载。因此,即使您可能具有非常不同的生命周期的非常特定的组件,也似乎所有Dagger配置都发生在ApplicationComponent和Application#onCreate中,而在其他任何地方都没有。