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依赖注入框架浅析
相关文章推荐
- Android快速开发框架
- Android快速开发框架
- android数据库sqlite的简单总结
- [android]_[ViewGroup的基本使用]
- Android自定义控件
- 安卓中的开发框架
- Android ListView显示底部的分割线
- Android ListView显示底部的分割线
- java.lang.illegalargumentexception view android.widget.listview is not a sliding drawer
- Android 自定义控件 轻松实现360软件详情页
- Android开发必知--使用View.setId的正确姿势
- Android 媒体 III-媒体路由提供者
- Android编程实用代码合集
- Android native splash for game
- Android逆向反编译之smali基础
- Android的事件分发源码分析,告别事件冲突。
- AndroidStudio 1.4配置NDK
- 生产实习(Android)八
- Android Studio 快捷键 for Mac OS X 10.5+
- Android Intent 的几种跳转