您的位置:首页 > 移动开发 > Android开发

Android Dagger 学习

2015-12-31 23:42 435 查看

概述

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

不仅麻烦,而且容易出错.这时候就体现了依赖注入的好处,如果还不太明白什么是依赖注入,请参考: 依赖注入,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依赖注入框架浅析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: