在TodoFluxArchitecture中使用Dagger2来完成依赖注入工作。Dagger2的上手比较难,深入的理解Dagger2是如何工作实在必行。这边文章主要以TodoFluxArchitecture中如何使用Dagger2做详细的介绍。文章中的代码块中只保留与Dagger2相关代码,如果分析有偏差,欢迎拍砖~~~
技术准备
在Dagger2中,需要使用注解来完成依赖注入,下面是我们在使用过程中总结的每个注解的作用。
@Inject
- 标注构造方法。当Dagger2需要被@Inject标注的类型完成依赖注入时,便会调用此构造方法,生成对应的对象。如果标注有参数的构造方法,Dagger2会在调用构造方法前,去获得参数对应的对象。所以,@Inject标注有参数构造方法时,需保证所有参数也提供可以被Dagger2调用的构造方法。Dagger2会为@Inject标注的每个类生成相关的Factory类,在Factory类中的get方法完成对象的创建。这一点可以关注文章中的ActionDispatcher,DataDispatcher和TodoStore和他们对应的Factory;
- 标注成员变量,说明这个成员变量需要Dagger2来通过注入的方式完成初始化,通常在ComeComponent.inject(object)时,自动完成注入。
@Module与@Provide
- @Module标注类,@Provide标注方法;
- @Module标注的类对Dagger2提供依赖,该类中@Provider标注的方法必须有返回值,这些方法的返回值是向Dagger2提供的具体依赖;
- Dagger2通过@Module和@Provider知道在哪里可以找到构造一个对象所需要的依赖;
- @Provider标注无参数方法时,直接返回已创建或者新创建的对象;
- @Provider标注有参数方法时,通常返回值是一个接口,参数是这个接口的具体实现类,同时具体实现类需要在构造方法标注@Inject。
- Dagger2为在Moudle中被@Provider标注的每个方法生成对应的SomeModule_方法名称Factory类,在后面会详细描述这块。
@Named
如果在Module中使用@Provider标注的两个方法返回类型是一样的,这个时候@Named就可以发挥作用啦。Dagger2根据@Named的参数做区分,在Component和@Inject标注的构造方法中,也需要使用@Named标注。使用TodoFluxArchitecture中,在Module中定义了两个返回类型为Dispatcher的方法,具体可参见项目中实现。
@Component
@Component是Dagger2中核心模块,是提供和@Module之间的桥梁,先简单描述@Component的用法,稍后来分析@Component的工作方式。
- @Component用于标注接口Component;
- 在Component接口中需要定义无参数只有返回类型的接口方法,如果返回类型相同需要@Named标注方法;
- 同时还需要定义有参数无返回值的inject接口方法;
- Dagger2会生成实现Component接口的类DaggerSomeComponent,其中会实现每个在Component中定义的接口方法;
- 暂时可以先了解这些,后面会更加详细的描述Dagger2通过@Component为我们做了哪些事情。
Module与Component
ApplicationModule和ApplicationComponent是android项目中必不可少的模块和组件,以它们为例来一步一分析。
ApplicationModule
1 |
|
在ApplicationModule中我们通过@Provider标注了很多方法,每个方法都存在返回值,具有参数的方法返回类型是一个接口,参数类型是对应接口的一种实现类,每个实现类的构造方法需要使用@Inject标注。actionDispatcher和dataDispatcher的返回类型都是Dispatcher,需要使用@Named标注以作区分。
ApplicationComponent
1 |
|
ApplicationComponent接口主要是定义很多接口方法,Dagger2会在具体类中实现每个接口方法,在每个接口方法的实现中完成获得创建的对象,细节稍后会描述。关于静态内部类Initializer是ApplicationComponent对外开放完成依赖注入的工具类。
被依赖类以及对应的Factory
在被依赖类的构造方法添加@Inject后,Dagger2会为被依赖类生成对应的Factory。
被依赖类
ActionDispatcher的相关代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14public class ActionDispatcher implements Dispatcher {
private Bus bus = new Bus(ThreadEnforcer.MAIN);
/**
* 构造事件分发器.
*/
public ActionDispatcher() {
LogTool.debug("构造 ActionDispatcher");
}
...
}
DataDispatcher的相关代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14public class DataDispatcher implements Dispatcher {
private Bus bus = new Bus(ThreadEnforcer.MAIN);
/**
* 构造数据分发器.
*/
public DataDispatcher() {
LogTool.debug("构造 DataDispatcher");
}
...
}
TodoStore的相关代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class TodoStore implements Store {
private Dispatcher dataDispatcher;
private Dispatcher actionDispatcher;
/**
* 构造TodoStore.
*
* @param dataDispatcher Data Dispatcher
* @param actionDispatcher Action Dispatcher
*/
public TodoStore(@Named("dataDispatcher") Dispatcher dataDispatcher,
@Named("actionDispatcher") Dispatcher actionDispatcher) {
LogTool.debug("构造 TodoStore");
this.dataDispatcher = dataDispatcher;
this.actionDispatcher = actionDispatcher;
}
...
}
- ActionDispatcher和DataDispatcher的构造方法是无参的;
- TodoStore的构造方法参数分别为actionDispatcher和dataDispatcher,依赖于actionDispatcher和dataDispatcher。
被依赖类对应的Factory
ActionDispatcher对应的Factory:1
2
3
4
5
6
7
8
9
10
11
12public enum ActionDispatcher_Factory implements Factory<ActionDispatcher> {
INSTANCE;
public ActionDispatcher get() {
return new ActionDispatcher();
}
public static Factory<ActionDispatcher> create() {
return INSTANCE;
}
}
DataDispatcher对应的Factory:1
2
3
4
5
6
7
8
9
10
11
12public enum DataDispatcher_Factory implements Factory<DataDispatcher> {
INSTANCE;
public DataDispatcher get() {
return new DataDispatcher();
}
public static Factory<DataDispatcher> create() {
return INSTANCE;
}
}
TodoStore对应的Factory:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public final class TodoStore_Factory implements Factory<TodoStore> {
private final Provider<Dispatcher> dataDispatcherProvider;
private final Provider<Dispatcher> actionDispatcherProvider;
public TodoStore_Factory(
Provider<Dispatcher> dataDispatcherProvider, Provider<Dispatcher> actionDispatcherProvider) {
assert dataDispatcherProvider != null;
this.dataDispatcherProvider = dataDispatcherProvider;
assert actionDispatcherProvider != null;
this.actionDispatcherProvider = actionDispatcherProvider;
}
public TodoStore get() {
return new TodoStore(dataDispatcherProvider.get(), actionDispatcherProvider.get());
}
public static Factory<TodoStore> create(
Provider<Dispatcher> dataDispatcherProvider, Provider<Dispatcher> actionDispatcherProvider) {
return new TodoStore_Factory(dataDispatcherProvider, actionDispatcherProvider);
}
}
从ActionDispatcher,DataDispatcher和TodoStore以及对应的Factory代码中,我们可以总结如下:
- @Inject标注ActionDispatcher和DataDispatcher的构造方法是无参数的;
- ActionDispatcher_Factory和DataDispatcher_Factory是使用枚举单例模式来创建对应的对象;
- 在ActionDispatcher_Factory和DataDispatcher_Factory中的get方法中直接创建对应对象返回;
- @Inject标注TodoStore的构造方法是有参数的,参数是actionDispatcher和dataDispatcher;
- TodoStore_Factory相对复杂一点,特殊的地方存在两个
Provider
,dataDispatcherProvider和actionDispatcherProvider; - Dagger2为TodoStore生成Factory时,发现TodoStore的构造方法需要参数,Dagger2为两个参数分别生成对应的
Provider
,Provider
由使用Factory的客户
传参到Factory;
进一步总结为:
- 使用@Inject标注被依赖类的无参数构造方法,Dagger2生成的Factory中get方法直接new 被依赖类的对象返回;
- 使用@Inject标注被依赖类的有参数构造方法,Dagger2生成的Factory创建时,需要提供参数的
Provider
,Provider
为new 被依赖类提供参数; - 那么Dagger2如何提供
Provider
呢?还在在后面详细描述。
Module类方法对应的Factory
通过上图我们可以确定,Dagger2为Module类中的@Provider标注的每个方法生成对应的Factory,Factory的名称规范为SomeModule_方法名称Factory。以application,actionDispatcher方法为例,看看Dagger2生成对应的Factory,主要关注Factory的create和get方法。
application方法对应的Factory:
1 | public final class ApplicationModule_ApplicationFactory implements Factory<Application> { |
create方法:
actionDispatcher方法对应的Factory:
1 | public final class ApplicationModule_ActionDispatcherFactory implements Factory<Dispatcher> { |
create方法:
- module和actionDispatcherProvider作为参数。
- 在actionDispatcher(ActionDispatcher actionDispatcher)方法生成Factory时,Dagger2发现此方法需要参数类型ActionDispatcher的对象,其依赖于外部提供;
- Provider
类型的actionDispatcherProvider由客户使用该Factory时确定。
get方法:
- 通过actionDispatcherProvider获得具体的ActionDispatcher对象actionDispatcher;
- 以actionDispatcher作为参数,通过module调用actionDispatcher方法。
Module类方法对应的Factory总结:
关键是在每个Factory的get方法中调用module的对饮的方法,例如ApplicationModule_ApplicationFactory调用module.application()方法,ApplicationModule_ActionDispatcherFactory调用module.actionDispatcher(actionDispatcherProvider.get())方法。
- 在module中@Provides标注的无参数方法生成的Factory直接通过module调用无参数方法来提供对象;
- 在module中@Provides标注的有参数方法生成针对接口的Factory,由外部客户提供Provider<> provider提供具体实现类,此时Factory只是对Provider的一种转接。
总结下来,目前Dagger2做了两件事情:
- 处理@Inject标注的构造方法,为每个类生成Factory;
- 为@Module标注的Module中被@Provides标注的方法,生成对应的Factory;
准备好相关的Factory后,我们来分析在Component中如何使用它们。
Component
Dagger2通过DaggerApplicationComponent实现了ApplicationComponent接口,来分析下DaggerApplicationComponent,在分析前,我们知道注入类FluxApplication的具体实现,同时建议大家再去熟悉下ApplicationComponent接口的定义.
注入的类FluxApplication
1 | public class FluxApplication extends Application { |
- @Inject标注成员变量,表示Dagger2帮助我们完成成员变量初始化工作;
- initInjector方法,通过ApplicationComponent.Initializer完成注入操作;
- 在initInjector方法调用后,便可以使用@Inject标注成员变量完成相关的业务操作.
生成的DaggerSomeComponent
1 | public final class DaggerApplicationComponent implements ApplicationComponent { |
- DaggerApplicationComponent是ApplicationComponent接口的实现类;
- DaggerApplicationComponent通过Builder模式完成创建;
- 在initialize时,会初始化
Module类方法对应的Factory
; - Module中有参数方法的
Module类方法对应的Factory
需要被依赖类以及对应的Factory
作为Provider参数完成create; - 每个实现的接口方法中,使用
Module类方法对应的Factory
来完成具体的实现; - 根据FluxApplication中@Inject标注的成员变量生成fluxApplicationMembersInjector;
- fluxApplicationMembersInjector.injectMembers(application)完成@Inject标注的成员变量的初始化,具体可参见FluxApplicationMembersInjectorF的具体实现.
Dagger2 到底做了些什么事情
下面是我总结的流程图:
- 为@Inject构造方法的类,我称呼为
被注入类
,生成对应的Factory,构造方法的参数也需要标注@Inject,也会生成对应的Factory; - 为@Inject标注成员变量的类,称呼为
注入类
,生成对应的MembersInjector类,实际上是在MembersInjector类中完成对成员变量的初始化; - 为Module中@Provides方法生成Factory;
- 为Component生成DaggerSomeComponent,在DaggerSomeComponent中,使用1和3中生成的Factory作为对象提供者,使用2中的MembersInjector完成对象初始化.
注
本篇文章是通过Dagger2生成的代码来分析Dagger2如何完成依赖注入,描述了最简单情况的整个流程.在实际项目中,可能存在Scope,Component依赖,Component与Module一对多等情况,通过分析生成的代码,可以很快了解它们如何发挥作用.