这个故事是该系列的第五部分,适用于 Android 初学者的 Dagger 2。 如果您没有阅读上一个,可以从下面开始。
系列目录
- 适用于 Android 初学者的 Dagger 2 - 简介
- 适用于 Android 初学者的 Dagger 2 - DI 第一部分
- 适用于 Android 初学者的 Dagger 2 - DI 第二部分
- 适用于 Android 初学者的 Dagger 2 - Dagger 2 第一部分
- 适用于 Android 初学者的 Dagger 2 — Dagger 2 第二部分 (你在这里)
- 适用于 Android 初学者的 Dagger 2 - Dagger 2 进阶第一部分
- 适用于 Android 初学者的 Dagger 2 - Dagger 2 进阶第二部分
Dagger2 前情回顾..
在上一讲中,我们讨论了手动使用 DI 如何会使我们的工作复杂化并增加样板代码。 然后我们讨论了 Dagger 2 将如何承担我们所有的痛苦并生成样板本身。我们还完成了注解处理基础知识和 Dagger 2 的基本注解。 然后我们在我们的示例中应用了这些注释,并使用 Dagger 2 注入了依赖项。
注意:如果你对我讲故事的方式感到不舒服 - 使用 权力的游戏 作为概念,请在后续阅读时随意更改类的名称。
DaggerBattleComponent 剖析
为了更好地理解 Dagger 2,让我们查看 DaggerBattleComponent
类。 'Control 或 Command +单击' DaggerBattleComponent
类。 您将看到以下代码段。
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerBattleComponent implements BattleComponent {
private DaggerBattleComponent(Builder builder) {}
public static Builder builder() {
return new Builder();
}
public static BattleComponent create() {
return new Builder().build();
}
//被实现的方法
@Override
public War getWar() {
return new War(new Starks(), new Boltons());
}
public static final class Builder {
private Builder() {}
public BattleComponent build() {
return new DaggerBattleComponent(this);
}
}
}
对于我们之前的硬依赖问题,这就是Dagger 2为我们生成的内容。 如果你看一下这个类实现的接口 - BattleComponent
- 这就是我们创建并请求Dagger通过方法 getWar()
为我们提供 War
依赖的东西。
这种依赖关系是通过构建器模式提供给我们的(您可以从这里和这里了解关于构建器模式的更多信息)。
现在是游戏时间!
让我们试着弄清楚并学习一些东西。 我希望你清楚地了解 getWar()
方法在类中的作用。现在,我还想要一些其他的依赖,即 Starks
和 Boltons
。 让我们创建这些接口方法并检查。
@Component
interface BattleComponent {
War getWar();
//添加更多方法
Starks getStarks();
Boltons getBoltons();
}
进行以下更改时,请单击 build 按钮。现在,让我们检查一下 DaggerBattleComponent 类。如果你做的对,你会看到一下内容。
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerBattleComponent implements BattleComponent {
private DaggerBattleComponent(Builder builder) {}
public static Builder builder() {
return new Builder();
}
public static BattleComponent create() {
return new Builder().build();
}
@Override
public War getWar() {
return new War(getStarks(), getBoltons());
}
@Override
public Starks getStarks() {
return new Starks();
}
@Override
public Boltons getBoltons() {
return new Boltons();
}
public static final class Builder {
private Builder() {}
public BattleComponent build() {
return new DaggerBattleComponent(this);
}
}
}
如果您注意到差异,Dagger 2 会重写所有方法(getStarks()
和 getBoltons()
)并返回正确的对象。
如果你问为什么以及如何? 好吧,我们告诉d agger 通过我们的 @Inject
注释来获取这些依赖项。 现在让我们做几件事。 从 Boltons
类中删除 @Inject
注解。 现在,点击 build 按钮。
什么都没发生?是的,你也许不会收到任何错误。尝试运行 BattleOfBastards
类 的 main 方法。您一定会收到以下错误。
如果你阅读了错误,它会清楚地告诉我们,如果没有提供 @Inject
或 @Provides
annotation,方法 getWar()
和 getBoltons()
将不起作用。
正如我们之前提到的,Dagger 2 与 Dagger 1 相比具有高度的错误可追溯性 - 证明是正确的。 你可以随意修改这个类。
@Module 和 @Provide 注解
让我们进一步了解一些有用的注解 - @Module 和 @Provide 注解。当您的项目规模增加时,您可能也在使用这些。
@Module
简而言之,@Module
注解标记了模块/类。 例如,让我们在Android中讨论一下。 我们可以有一个名为 ContextModule
的模块,该模块可以为其他类提供 ApplicationContext
和 Context
依赖项。 所以我们需要用 @Module
标记 ContextModule
类。
@Provides
简而言之,@Provides
注解标记模块内部提供依赖项的方法。例如,在上面的相同示例中,我们使用 @Module
标记了 ContextModule
,我们需要使用 @Provides
标记提供 ApplicationContext
和 Context
的方法。
让我们看一个小例子(参考下面的分支)
例子
让我们来看看 Braavos 提供的两项服务 - Cash 和 Soldiers (我不知道他们是否装钱或军队,我们只考虑这个例子)。 我创造了两个类 Cash 和 Soldiers。
public class Cash {
public Cash(){
//do something
}
}
public class Soldiers {
public Soldiers(){
//do something
}
}
现在,让我们创建一个名为 BraavosModule
的模块,该模块为其他类提供两个依赖项- Cash
和 Soldiers
。
@Module //模块
public class BraavosModule {
Cash cash;
Soldiers soldiers;
public BraavosModule(Cash cash, Soldiers soldiers){
this.cash=cash;
this.soldiers=soldiers;
}
@Provides //提供 cash 依赖项
Cash provideCash(){
return cash;
}
@Provides //提供 soldiers 依赖项
Soldiers provideSoldiers(){
return soldiers;
}
}
正如我们之前看到的,我们需要使用 @Module 注解标记所有模块,并使用 @Provides 注解标记提供依赖项的方法。
让我们跳转到我们的 BattleOfBastards
类,并让 component 实现方法 provideCash()
和 provideSoldiers()
。
@Component(modules = BraavosModule.class)
interface BattleComponent {
War getWar();
Cash getCash();
Soldiers getSoldiers();
}
public class BattleOfBastards {
public static void main(String[] args){
Cash cash = new Cash();
Soldiers soldiers = new Soldiers();
BattleComponent component = DaggerBattleComponent
.builder().braavosModule(new BraavosModule(cash, soldiers)).build();
War war = component.getWar();
war.prepare();
war.report();
//使用 cash 和 soldiers
component.getCash();
component.getSoldiers();
}
}
另外,请注意我已将 module 包含在了 component 语句中。 这是为了通知该 component 包括以下module。
@Component(modules = BraavosModule.class)
添加这些之后,再次 build 项目。您将在 DaggerBattleComponent
的 .create()
中看到错误。这是因为,添加 module 时,我们需要将 module 依赖项传递给dagger。我们需要像这样传递它。
BattleComponent component = DaggerBattleComponent
.builder().braavosModule(new BraavosModule(cash, soldiers)).build();
所有 modules 后,您可以开始使用该 component 的方法。
component.getCash();
component.getSoldiers();
如果您想查看 DaggerBattleComponent
类
(ctrl/cmd+单击),您会注意到该模块 BraavosModule
已被包含并派生,以提供 Cash
和 Soldier
相关性。
总结
我们分析了由 dagger 生成的类的解剖结构,发现了 dagger 如何利用构建器模式来为我们提供所需的依赖项。
我们还看到了使用 @module
和 @provides
注解的基本示例。
下一步是什么?
接下来,我们将看到使用 Dagger 2 的实时 Android 示例。敬请关注!