Dagger2

Dependency Injection

Dependency指的是一个可以用的对象,也叫服务。Injection指的是把依赖传递给需要使用它的dependent对象,也叫客户端。服务是客户端状态的一部分。

依赖注入模式的基本要求是把服务传递给客户端,而不是让客户端自己去创建或者寻找服务。

这个基本要求也就意味着在不允许类内部使用new或者static方法去产生服务。该类应该从外部接收服务,因此服务的获取是其他类的职责。

依赖注入原则的目的是创建和使用的解耦,达到一种境界,就是当客户端所依赖的对象需要变成另一个的时候,客户端的代码也无需修改。

Dagger2是用来实现Dependency Injection模式的库。依赖注入一方面可以方便测试,另一方面可以创建可复用可更换的模块。

Dagger2的具体实现是在编译期生成代码。

导入

Java Gradle

// Add plugin https://plugins.gradle.org/plugin/net.ltgt.apt
plugins {
  id "net.ltgt.apt" version "0.10"
}

// Add Dagger dependencies
dependencies {
  compile 'com.google.dagger:dagger:2.x'
  apt 'com.google.dagger:dagger-compiler:2.x'
}

Android Gradle

dependencies {
  compile 'com.google.dagger:dagger:2.x'
  annotationProcessor 'com.google.dagger:dagger-compiler:2.x'

  // 如果要使用dagger.android还需要导入
  compile 'com.google.dagger:dagger-android:2.x'
  compile 'com.google.dagger:dagger-android-support:2.x' // 如果使用支持库
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
}

如果使用了DataBinding,可以通过以下方式增加javac所会打印的错误行数:

gradle.projectsEvaluated {
  tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xmaxerrs" << "500" // or whatever number you want
  }
}

使用步骤

1. 声明依赖

Dagger可以创建所需要的类实例,满足所需要的依赖。它使用javax.inject.Inject来识别目标构造方法和需要的字段。

使用@Inject来标注用来创建类实例的构造方法,需要创建类实例的时候,Dagger会去获取需要的参数值,然后调用这个构造方法。

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

Dagger可以直接注入字段,比如下面这段代码就是给heater这个字段获取一个Heater实例,给pump这个字段获取一个Pump实例。

class CoffeeMaker {
  @Inject Heater heater;
  @Inject Pump pump;

  ...
}

如果类中有@Inject注解的字段,但是没有@Inject注解的构造方法,Dagger会在需要的时候注入@Inject注解字段,但是不会创建新的实例。新添一个@Inject注解的无参构造函数来表示说Dagger也可以创建新实例。

Dagger也支持方法注入,尽管比较少用。

缺少@Inject注解的类不能被Dagger构造出来。

2. 满足依赖

默认情况下,Dagger通过构建所需要类型的实例来满足依赖,如果你要求一个CoffeeMaker实例,Dagger就会调用new CoffeeMaker(),然后设置可注入字段。

@Inject在以下情况下不管用:

  • 接口没办法被实例化
  • 第三方类没办法被注解
  • 可配置的类必须被配置

在这些@Inject无能为力的情况下,可以使用@Provides注解方法来满足依赖条件,所注解的方法返回需要的依赖类。

@Provides static Heater provideHeater() {
  return new ElectricHeater();
}

比如说需要一个Heater的时候就会去调用provideHeater()。

@Provides所注解的方法也可能有自己的依赖,比如说

@Provides static Pump providePump(Thermosiphon pump) {
  return pump;
}

所有的@Provides注解方法必须声明在一个注解了@Module的类当中

@Module
class DripCoffeeModule {
  @Provides static Heater provideHeater() {
    return new ElectricHeater();
  }

  @Provides static Pump providePump(Thermosiphon pump) {
    return pump;
  }
}

根据习惯,@Provides注解的方法都用provide开头,@Module注解的类都用Module结尾。

3. 构建图表

使用@Inject和@Provides注解的类相互之间通过依赖关系联系在了一起。Dagger2通过一个注解了@Component的接口来获取需要的类。该接口中的方法都没有参数,返回的是所需要的类型。@Component注解需要指明返回的module类名,如有多个使用逗号分开:

@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
  CoffeeMaker maker();
}

这样会生成一个Dagger+Component名的类用来获取想要的对象:

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
    .dripCoffeeModule(new DripCoffeeModule())
    .build();

注意,如果@Component注解的类是内部类的话,还需要加上外部类的类名,以下划线连接,例如:

class Foo {
  static class Bar {
    @Component
    interface BazComponent {}
  }
}

那生成类的类名就是DaggerFoo_Bar_BazComponent。

Module类自带的可获取的构造方法都可以直接省略掉,因为如果没有设置的话,builder可以直接创建一个实例。

如果Module类的@Provides方法都是static的,那就不需要builder去创建实例了,直接使用create()即可:

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

使用示例:

public class CoffeeApp {
  public static void main(String[] args) {
    CoffeeShop coffeeShop = DaggerCoffeeShop.create();
    coffeeShop.maker().brew();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值