适用于 Android 初学者的 Dagger 2 - Dagger 2 第二部分

原文链接

这个故事是该系列的第五部分,适用于 Android 初学者的 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 或 @Providesannotation,方法 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 示例。敬请关注!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值