概述
在开发的过程中.我们都需要用到很多对象,在使用之前都需要初始化.如果这个对象需要在多处被使用,那么在每个地方都要写相同的代码,而且当我们需要改变其中某个类的功能的时候,就需要更改大量的代码
不仅麻烦,而且容易出错.这时候就体现了依赖注入的好处,如果还不太明白什么是依赖注入,请参考: 依赖注入,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依赖注入框架浅析