Android 依赖注入框架 Dagger 学习

概述

在开发的过程中.我们都需要用到很多对象,在使用之前都需要初始化.如果这个对象需要在多处被使用,那么在每个地方都要写相同的代码,而且当我们需要改变其中某个类的功能的时候,就需要更改大量的代码

不仅麻烦,而且容易出错.这时候就体现了依赖注入的好处,如果还不太明白什么是依赖注入,请参考: 依赖注入,Dagger就是一款依赖注入框架

Dagger

dagger的用途就是 你不用初始化对象,达到成员变量申明就能用.dagger通过依赖注入构建对象图表,降低了程序的耦合性.

通过inject()方法自动注入所有对象,完成自动的初始化。

Dagger使用 @Inject 注释的构造函数 创建类对象。 当请求构建新的类对象时, Dagger 将自动获取相应的参数, 并调用构造函数。

 class  A{
        @Inject
        public A() {        
        }
    }
public class MainActivity extends Activity {  
    @Inject A a;  
}  

以上面的代码为例,在Activity中实例化A的对象,只需要@Inject 即可,dagger会自动找到被标记的构造函数并调用来获取实例.
如果构造函数中包含有参数.需要这个参数的构造函数也有@Inject标记.或者可以通过@Provides 标记来获取实例

官方示例

dagger 官方示例采用了煮咖啡来讲解dagger的工作原理.

class Thermosiphon implements Pump {
  private final Heater heater;

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

  @Override public void pump() {
    if (heater.isHot()) {
      System.out.println("=> => pumping => =>");
    }
  }
}

这里提供了一个Pump 实现类的注入入口.同时又依赖于Heater

class CoffeeMaker {
  @Inject Lazy<Heater> heater; // Don't want to create a possibly costly heater until we need it.
  @Inject Pump pump;

  public void brew() {
    heater.get().on();
    pump.pump();
    System.out.println(" [_]P coffee! [_]P ");
    heater.get().off();
  }
}

获取Heater对象, 并注入到成员变量heater,同时获取Pump对象并注入到成员变量pump。
pump 的依赖上面已经标注,那么我们来看一下heater的实现

class ElectricHeater implements Heater {
  boolean heating;

  @Override public void on() {
    System.out.println("~ ~ ~ heating ~ ~ ~");
    this.heating = true;
  }

  @Override public void off() {
    this.heating = false;
  }

  @Override public boolean isHot() {
    return heating;
  }
}

可以看到 heater中是没有@Inject 标记的.

注意:类中含有@Inject注释的成员变量, 却没有@Inject注释的构造函数时, Dagger将使用类的默认构造函数。若类中缺少@Inject注释, 该类是不能由Dagger创建的。
Dagger 通过构造相应类型的对象来实现依赖关系,那么heater是怎么引入的呢,上面我们说过还有一种方式那就是通过@Provides 标记

自定义依赖(Provides)

构造方法进行@Inject注解是很好用的实现依赖的途径,然而它并不适用于所有情况

  • 接口类型不能被构造(接口当然不能构造对象)
  • 第三方的类不能被注释构造(第三方的类显然不能加入@Inject注释, 当然也不能被Dagger构造.)
  • 可配置的对象必须被配置好(有些类需要灵活的初始化配置,而不是使用一个单一的构造函数)

对那些使用@Inject效率极低或者awkward的情况,dagger使用了@Provides来实现依赖关系,我们来看一下heater的provide方法

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

Dagger支持单例,实现方式也十分简单,通过注解@Singleton,对象只会被初始化一次,之后的每次都会被直接注入相同的对象。

同样,@Provides注解的方法如果含有参数,它的所有参数也要保证能够被Dagger获取到。

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

Module

所有的@Provides函数必须属于一个Module。这些Module类使用@Module注释。

通常情况下, 约定@Provides函数以provide作为前缀, @Module类以Module作为后缀。

@Module(
    injects = CoffeeApp.class,
    includes = PumpModule.class
)
class DripCoffeeModule {
  @Provides @Singleton Heater provideHeater() {
    return new ElectricHeater();
  }
}

注意:

  • 所有含有依赖注入的类,都必须显示申明在Module 中
  • 一个Module中所有@Provides方法的参数都必须在这个Module中提供相应的@Provides方法,
    或者在@Module注解后添加“complete = false”注明这是一个不完整Module(即它会被其他Module所扩展)
  • 一个Module中所有的@Provides方法都要被它声明的注入对象所使用,或者在@Module注解后添加“library = ture”注明(即它是为了扩展其他Module而存在的)

ps:

@Module(complete = false, library = true)
class PumpModule {
  @Provides Pump providePump(Thermosiphon pump) {
    return pump;
  }
}

这个Module就是为了扩展DripCoffeeModule而存在的,上面的injects选项使得可以在编译的过程中检查对象图表是有有效

ObjectGraph(对象图表)

@Inject@Provides 注释的类构建了一个对象图表。这些对象与对象之间通过依赖关系相互关联。
通过函数ObjectGraph.create()获取这个对象图表, 这个函数可以接受一个或多个Module作为参数

public class CoffeeApp implements Runnable {
  @Inject CoffeeMaker coffeeMaker;

  @Override public void run() {
    coffeeMaker.brew();
  }

  public static void main(String[] args) {
    ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());
    CoffeeApp coffeeApp = objectGraph.get(CoffeeApp.class);
    coffeeApp.run();
  }
}

这里面直接通过objectGraph.get(CoffeeApp.class) 来获取CoffeeApp 的实例,而我们的对象图表中并没有被引导注入
需要在Module中显示的申明,上面 injects = CoffeeApp.class, 就是这个作用

LAZY INJECTIONS(懒加载)

Sometimes you need an object to be instantiated lazily. For any binding T, you can create a Lazy which defers instantiation until the first call to Lazy’s get() method. If T is a singleton, then Lazy will be the same instance for all injections within the ObjectGraph.

懒加载, 等到调用的时候才注入

class GridingCoffeeMaker {
  @Inject Lazy<Grinder> lazyGrinder;

  public void brew() {
    while (needsGrinding()) {
      // Grinder created once on first call to .get() and cached.
      lazyGrinder.get().grind();
    }
  }
}

PROVIDER INJECTIONS(提供者注入 )

Sometimes you need multiple instances to be returned instead of just injecting a single value. While you have several options (Factories, Builders, etc.) one option is to inject a Provider instead of just T. A Provider creates a new instance of T each time .get() is called.

有些情况下, 你需要多个对象实例, 而不是仅仅注入一个对象实例。这时你可以利用Provider实现, 每次调用Provider的get()函数将返回新的的对象实例。

class BigCoffeeMaker {
  @Inject Provider<Filter> filterProvider;

  public void brew(int numberOfPots) {
    ...
    for (int p = 0; p < numberOfPots; p++) {
      maker.addFilter(filterProvider.get()); //new filter every time.
      maker.addCoffee(...);
      maker.percolate();
      ...
    }
  }
}

QUALIFIERS(限定符)

区分不能通过类型来获取具体依赖的情况

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
  String value() default "";
}

我们的Module

@Provides @Named("hot plate") Heater provideHotPlateHeater() {
  return new ElectricHeater(70);
}

@Provides @Named("water") Heater provideWaterHeater() {
  return new ElectricHeater(93);
}

@Inject 引用,就是通过新增一个新注解,来获取我们想要的实例

class ExpensiveCoffeeMaker {
  @Inject @Named("water") Heater waterHeater;
  @Inject @Named("hot plate") Heater hotPlateHeater;
  ...
}

参考:

Dagger——Android上的依赖注入框架
Dagger - 快速依赖注入器(for android and java) (1)
Dagger官方文档
Android Dagger依赖注入框架浅析

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值