gpt4 book ai didi

android - 在Android的Application类中为DI创建所有模块

转载 作者:行者123 更新时间:2023-11-29 23:22:15 24 4
gpt4 key购买 nike

我注意到许多开发人员要做的一件事是创建一个从Application继承的类,然后通过依赖项注入创建一个组件,该组件实际上包括组成其应用程序的所有模块。这是在onCreate方法中完成的。我觉得这很奇怪。为什么要将每个模块注入Application类并使其全局可用。毕竟,大多数模块(例如演示者)都绑定到单个活动,并且永远不会用于任何其他活动。那么,为什么不只在活动中创建一个组件,而只包含所需的那些模块,在活动中,这将是一个presenter类。

最佳答案

我不确定是否同意以下前提:大多数应用程序在Application#onCreate中创建一个组件,但是我相信大多数应用程序还具有单独的组件,这些组件包含按活动,按碎片或按服务的绑定,以及这些组件/ modules仅存在,并且仅在您使用有问题的特定活动/片段/服务时才进行类加载。

范围和生命周期

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将需要分析整个应用程序的依赖关系图。

应用程序#onCreate

所有这些都返回到Application#onCreate和您所看到的:


如果您有应用程序范围内的单例,则可能需要从应用程序中获取它们(尽管从技术上讲,您也可以使用静态字段)。
如果您有在整个应用程序中使用的绑定,即使它们没有作用域,则您可能只想将它们安装在ApplicationComponent中,这样就不必在每个组件中重复相同的绑定。
如果您使用的是子组件,则整个应用程序的所有代码生成都是在应用程序级别一步生成的,即使代码是作为在单独的时间加载的单独的类生成的。因为应用程序组件充当工厂,所以多余的类被隐藏了,因为您对生成的类名的唯一引用可能是针对ApplicationComponent实例(“ DaggerApplicationComponent”)。


这可能会带来更流畅的开发人员体验,因为如果要从ActivityComponent访问它,则无需担心在ApplicationComponent接口上列出依赖项。
这对于Android也很好,因为在子组件的情况下,Dagger提供了有关需要哪些绑定的更多信息,因此有时它可以生成比依赖组件更紧凑的代码。
如果使用的是 dagger.android@ContributesAndroidInjector,则使用的子组件的顶部带有一些语法糖。请注意, @ContributesAndroidInjector可以使用范围注释进行注释,并且可以采用 modules的列表,该列表将传递到它生成的子组件。您对 AndroidInjection.inject(this)的调用将创建这些子组件实例之一,并根据需要对子组件及其模块进行类加载。



因此,即使您可能具有非常不同的生命周期的非常特定的组件,也似乎所有Dagger配置都发生在ApplicationComponent和Application#onCreate中,并且没有其他地方。

关于android - 在Android的Application类中为DI创建所有模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54106557/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com