依赖(Dependency):如果在 Class A 中,有个属性是 Class B 的实例,则称 Class B 是 Class A 的依赖,本文中我们将 Class A 称为宿主(Host),并且全文用 Host 表示;Class B 称为依赖(Dependency),并且全文用 Dependency 表示。一个 Host 可能是另外一个类的 Dependency。 宿主(Host):如果 Class B 是 Class A 的 Dependency,则称 Class A 是 Class B 的宿主(Host)。 依赖注入:如果 Class B 是 Class A 的 Dependency,B 的赋值不是写死在了类或构造函数中,而是通过构造函数或其他函数的参数传入,这种赋值方式我们称之为依赖注入。
更详细介绍可见 依赖注入简介。
1.3 Dagger 基本使用
本文将以一个简单的“老板和程序员” App 为例。
Activity 中有一个 Boss 类属性,现在你想把一个 Boss 对象注入到这个 Activity 中,那么有两个问题需要解决:Boss 对象应该怎样被生成 以及 Boss 对象怎样被设置到 Activity 中。
(1). Boss 对象怎样生成
在 Boss 类的构造函数前添加一个 @Inject 注解,Dagger 就会在需要获取 Boss 对象时,调用这个被标记的构造函数,从而生成一个 Boss 对象。
public class Boss {...@Injectpublic Boss() {...}...}需要注意的是,如果构造函数含有参数,Dagger 会在调用构造对象的时候先去获取这些参数(不然谁来传参?),所以你要保证它的参数也提供可被 Dagger 调用到的生成函数。Dagger 可调用的对象生成方式有两种:一种是用 @Inject 修饰的构造函数,上面就是这种方式。另外一种是用 @Provides 修饰的函数,下面会讲到。
(2). Boss 对象怎样被设置到 Activity 中
通过 @Inject 注解了构造函数之后,在 Activity 中的 Boss 属性声明之前也添加 @Inject 注解。像这种在属性前添加的 @Inject 注解的目的是告诉 Dagger 哪些属性需要被注入。
public class MainActivity extends Activity {@Inject Boss boss;...}最后,我们在合适的位置(例如 onCreate() 函数中)调用 ObjectGraph.inject() 函数,Dagger 就会自动调用上面 (1) 中的生成方法生成依赖的实例,并注入到当前对象(MainActivity)。
public class MainActivity extends Activity {@Inject Boss boss;@Overrideprotected void onCreate(Bundle savedInstanceState) {ObjectGraph.create(AppModule.class).inject(this);}...}具体怎么注入即设置的过程后面会详细介绍,这里简单透露下,APT 会在 MainActivity 所在 package 下生成一个辅助类 MainActivity$$InjectAdapter,这个类有个 injectMembers() 函数,代码类似:
public void injectMembers(MainActivity paramMainActivity) {paramMainActivity.boss = ((Boss)boss.get());……}上面我们已经通过 ObjectGraph.inject() 函数传入了 paramMainActivity,并且 boss 属性是 package 权限,所以 Dagger 只需要调用这个辅助类的 injectMembers() 函数即可完成依赖注入,这里的 boss.get() 会调用 Boss 的生成函数。
到此为止,使用 Dagger 的 @Inject 方式将一个 Boss 对象注入到 MainActivity 的流程就完成了。
对于以上三种情况,可以使用 @Provides 注解来标记自定义的生成函数,从而被 Dagger 调用。形式如下:
@ProvidesCoder provideCoder(Boss boss) {return new Coder(boss);}和构造函数一样,@Provides 注解修饰的函数如果含有参数,它的所有参数也需要提供可被 Dagger 调用到的生成函数。
需要注意的是,所有 @Provides 注解的生成函数都需要在Module中定义实现,这就是上面提到的 Module 的作用之一——让 ObjectGraph 知道怎么生成某些依赖。
@Modulepublic class AppModule {@ProvidesCoder provideCoder(Boss boss) {return new Coder(boss);}}
(2). @Inject 和 @Provide 两种依赖生成方式区别
a. @Inject 用于注入可实例化的类,@Provides 可用于注入所有类
b. @Inject 可用于修饰属性和构造函数,可用于任何非 Module 类,@Provides 只可用于用于修饰非构造函数,并且该函数必须在某个Module内部
c. @Inject 修饰的函数只能是构造函数,@Provides 修饰的函数必须以 provide 开头
1.5 单例
Dagger 支持单例(事实上单例也是依赖注入最常用的场景),使用方式也很简单:
// @Inject 注解构造函数的单例模式@Singletonpublic class Boss {...@Injectpublic Boss() {...}...}// @Provides 注解函数的单例模式@Provides@SingletonCoder provideCoder(Boss boss) {return new Coder(boss);}在相应函数添加 @Singleton 注解,依赖的对象就只会被初始化一次,之后的每次都会被直接注入相同的对象。
Dagger 的运作机制,是运用 APT(Annotation Process Tool) 在编译时生成一些用于设定规则的代码,然后在运行时将这些规则进行动态组合 // TODO 不太理解意思,生成一个(或多个)DAG,然后由 DAG 来完成所有依赖的获取,实现依赖注入。关于 DAG 究竟是怎样一步步生成的,后面再讲,这里先说一下在 Dagger 中依赖注入与 DAG 的关系。