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

原文链接

这个故事是该系列的第四部分,适用于 Android 初学者的 Dagger 2。 如果您没有阅读上一篇文章,可以从这里开始。

系列目录

Dagger2 前情回顾..

在之前一讲中,我们理解了该类本生不应该创建或持有自己的依赖。 相反,它需要从外部获取它。

我们还看到了简单依赖注入的计划。 我们以 私生子之战 为例,试图通过 DI 消除对 class 的严重依赖。

注意:如果你对我讲故事的方式感到不舒服 - 将 权力的游戏 作为概念,请在后续阅读时随意更改类的名称。

依赖注入如何变得复杂?

如果项目与前面的示例一样简单,那么在 main 方法上手动实例化和注入一些依赖项是非常合理的。 但是,大多数项目都有几十个类,每个类都有各种需要满足的依赖项。 实例化和连接所有内容需要大量代码。 更糟糕的是,每次将新类添加到应用程序时或每次修改现有类以需要新依赖项时,此代码都将不断更改。

为了说明这个问题,让我们的小例子稍微复杂一些。 在战争中 -  BattleOfBastards 可能需要 Alliesto 的支持。 此外,IronBank 将资助房屋或其他东西。 修改后的 main 函数如下所示:

public class BattleOfBastards {

    public static void main(String[] args){
        IronBank bank = new IronBank();
        Allies allies = new Allies(bank);
        Starks starks = new Starks(allies, bank);
        Boltons boltons = new Boltons(allies, bank);

        War war = new War(starks, boltons);
        war.prepare();
        war.report();
    }
}

很快,我们的应用程序的入口点开始因初始化代码而变得臃肿。 要构建一个我们真正关心的对象类,我们必须手动实例化其他许多类。 随着应用程序的增长和更多类的添加,这个 mian 方法将继续增长,直到它变得完全无法管理。

Dagger2 前来救援

Dagger 2 是开源 DI 框架之一,它为我们生成了大量的样板文件。 但为什么它比其他的更好? 现在,它是唯 一 一 个在 Java 中生成完全可跟踪源代码的 DI 框架,它模仿用户可以手动编写的代码。 这意味着依赖图构造中没有魔力。 Dagger 2 的动态性低于其他的库(根本没有反射用法),但生成的代码的简单性和性能与手写代码处于同一级别。 简而言之,Dagger 2为您生成所有依赖注入样板。

换言之,手动管理依赖注入就像,挖掘龙玻璃-获得龙皇后的许可,然后将其锻造成武器,然后与 White Walkers 战斗(硬依赖问题)。Dagger 2 框架就像是 valyrian 之剑-它是由大师创造的,你只需要使用它。

理解注解处理器

#注解

注解是元数据类,可以与类,方法,变量甚至其他注解相关联。 Java 中的注解用于提供附加信息,因此它是 XML 和 Java 标记接口的另一种选项。 也可以在运行时通过反射访问这些方法。

#注解处理器

注解处理器是通过在编译期间为您创建代码来消除样板代码的代码生成器。 由于它是编译时,因此性能没有任何开销。

#为什么我应该了解注解处理器?

Dagger 2 适用于注解处理器。 因此,所有在编译时的代码生成都是可追踪的。 因此,您没有性能开销,并且其错误具有高度可跟踪性。

#例子

您经常会在类中看到 @Override  - 这是一个注解。 同样,如果您使用过 Butterknife,那么 @BindView 也是一个注解,带有很少的元数据,这将有助于为您生成代码。

理解 Dagger 2 注解

Dagger 2 API 中几乎没有注解。我们开始研究每一项注解时都要去查看他们。现在,让我们集中讨论2个注解-  @Inject   @Component。

@Inject 注解

第一个也是对 DI 最重要的是@Inject 注解。JSR-330 标准的一部分标记了那些应该由依赖注入框架提供的依赖项。

  • 构造函数注入 - 与类构造函数一起使用
  • 变量  - 与类中的变量一起使用
  • 方法注入 - 与函数/方法一起使用
ublic class Starks{
  /**
   * 解释注入匕首 Inject 注解的不同用法
   */
  
  //变量注入
  @Inject
  Allies allies;
  
  //构造函数注入
  @Inject
  public Starks(){
    //做点什么..
  }
  
  //方法注入
  @Inject
  private void prepareForWar(){
    //做点什么..
  }
}

换句话说,@Inject 注解将告诉 Dagger 需要将哪些依赖项转移到依赖者。这就像是 iron bank 的现场代理,与家族谈判并确定他们可以提供的贷款金额。

@Component 注解

此注解用于构建将所有内容连接在一起的接口。 在这个地方,我们定义了从哪些模块(或其他 Components)中获取依赖关系。 此外,还可以定义哪些图形依赖项应该公开显示(可以注入)以及我们的组件可以注入对象的位置。 一般来说,@Component 是 @Module(我们稍后会看到)和 @Inject.之间的桥梁。

换句话说, @Component 注解是负责批准和转移贷款金额到 iron bank 各自账户的代理人。

用 Valyrian 剑杀死WhiteWalkers

让我们使用 Dagger 2 作为 BattleOfBastards 示例。 在我们的基本示例中,我们需要两个类作为类 War 的依赖项  -  Starks 和 Boltons。 然后我们将为所有人提供 War 的对象。

#设置 Dagger 2

要在 IntelliJ Idea 中设置 Dagger,请参阅以下项目分支的 build.gradle 文件。 此外,请确保在 Preferences - >Build,execution and deployment - >Compiler - >Annotation Processing - >Enable annotation processing(应该勾选上)

此外, 确保 Preferences -> Build, execution and deployment -> Gradle -> Runner ->Delegate IDE build/run actions to cradle (应该勾选上)

#添加 @Inject 注解

The plan is to make the dependencies — Starks and Boltons inject into the Class War. So we need to tell Dagger 2 that these are the dependencies that need to be injected. So we’ll be using the @inject annotation and let the API know. Here’s how we need to add it (we’re using constructor injection).计划是使依赖 - Starks 和 Boltons 注入 Class War。 所以我们需要告诉 Dagger 2 这些是需要注入的依赖项。 所以我们将使用 @inject 注解并让 API 知道。 这是我们需要添加它的方式(我们正在使用构造函数注入)。

public class Boltons implements House {

   @Inject
   public Boltons(){
    }

    @Override
    public void prepareForWar() {
        //do something
        System.out.println(this.getClass().getSimpleName()+" prepared for war");
    }

    @Override
    public void reportForWar() {
        //do something
        System.out.println(this.getClass().getSimpleName()+" reporting..");
    }
}
public class Starks implements House {

    @Inject //Dagger 2
    public Starks(){
    }

    @Override
    public void prepareForWar() {
        //do something
        System.out.println(this.getClass().getSimpleName()+" prepared for war");
    }

    @Override
    public void reportForWar() {
        //do something
        System.out.println(this.getClass().getSimpleName()+" reporting..");
    }
}

这两个依赖项,去了 Class War。 因此我们需要在 War 类构造函数中将其标记为 inject。

计划是使所有其他类可以使用  Class War  的依赖或对象。 但是要使  Class War  起作用,你需要 Class War Starks 和 Boltons)的依赖 - 只有这样它才能参与
public class War {

    private Starks starks;

    private Boltons boltons;

    @Inject
    public War(Starks starks, Boltons bolton){
        this.starks = starks;
        this.boltons = bolton;
    }

    public void prepare(){
        starks.prepareForWar();
        boltons.prepareForWar();
    }

    public void report(){
        starks.reportForWar();
        boltons.reportForWar();
    }

}

#添加 @Component 注解

正如我们之前看到的,component 是生成的代码和依赖项之间的桥梁。 这些 components 还告诉 Dagger,需要如何注入依赖关系。 为此,让我们创建一个 BattleComponent 接口 - 在BattleOfBastards 类中(也可以单独创建)。

@Component
interface BattleComponent {
    War getWar();
}

BattleComponent 接口将由 Dagger2 将为我们为生成(是的,dagger 2 将为我们创建样板)的类来实现,函数 getWar() 将返回 War 对象,以便我们可以在适当的位置使用它。

现在你需要 rebuild 项目!

在重新构建之后,Dagger 2 将生成一个名为 DaggerBattleComponent  的类 - 这将帮助我们注入 War 对象。 现在,让我们使用这个类来获取 War 实例。

@Component
interface BattleComponent {
    War getWar();
}

public class BattleOfBastards {

    public static void main(String[] args){
//        手动 DI
//        Starks starks = new Starks();
//        Boltons boltons = new Boltons();
//        War war = new War(starks,boltons);
//        war.prepare();
//        war.report();

//      Using Dagger 2
        BattleComponent component = DaggerBattleComponent.create();
        War war = component.getWar();
        war.prepare();
        war.report();

    }
}

使用 DaggerBattleComponent 类,我们现在能够使用方法 getWar(),其中此方法返回对象 War,它提供依赖关系 -  Starks 和 Boltons

祝贺你!,现在您已经使用 Dagger 2 创建了第一个项目。我真的很感谢你花费时间并走到这一步。是时候庆祝了。

总结

我们讨论了手动使用 DI 将怎样使我们的工作复杂化并增加样板代码。然后我们讨论了 Dagger 2 如何承受我们所有的痛苦并生成样板。

接下来,我们介绍了注解处理基础知识和 Dagger 2 的基本注解(Inject 和 Component)。然后我们在示例中应用了这些注解,并使用 Dagger 2  注入依赖项。

下一步是什么?

下一讲,我们将使用生成的 dagger component 类,我们将看到关于 Dagger 2 的其他注解的更多信息。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值