关于Dagger2
- Dagger基础用法
- 对注解的分类讲解——Inject部分
- 对注解的分类讲解——Module部分(一)
- 对注解的分类讲解——Component部分
- 对注解的分类讲解——Module(二)
- 对注解的分类讲解——Module(三)
- 对Dagger中几个类的说明
- Dagger-Android的使用
前言
本文将通过对注解的分类讲解来交代Dagger2的进阶用法。
关于Dagger的注解,简单将它们分成三类:
- Component部分
- Module部分
- Inject部分
来对应Dagger完成依赖注入的三部分内容,讲完了Inject注入部分,接下来就来看看Component中间件部分。
Component部分注解
Component部分用于将Module和依赖建立起联系,起着至关重要的作用。
@Component
@Component注解的接口类,会生成以Dagger为前缀的Component实现类,@Component注解只能用在接口或抽象类上。
举个简单例子:
// @Component注解,modules参数用设置需要进行对象查找的Module
@Component(modules = {MainModule.class})
public interface MainComponent {
// 定义与Activity建立链接的方法
void inject(MainActivity activity);
}
当然上面这个例子只是简单的一个用来建立链接的Component,Component还有其它的一些复杂使用。
来看一看@Component注解中都包含了哪些内容:
@Retention(RUNTIME)
@Target(TYPE)
@Documented
public @interface Component {
// 用于指定需要建立链接的Modules
Class<?>[] modules() default {};
// 用于获取其它的Component所提供的依赖对象
Class<?>[] dependencies() default {};
// 如果不想要通过Module获取对象,可以通过Builder的方式在插入时获取,需要和@BindsInstance注解配合使用
@Retention(RUNTIME)
@Target(TYPE)
@Documented
@interface Builder {}
// 与Builder相似,通过工厂的方式来获取对象
@Retention(RUNTIME)
@Target(TYPE)
@Documented
@interface Factory {}
}
@Component.Builder
Dagger提供了@Component.Builder注解可以让我们来自定义对象的构建过程:
@Component
public interface ComponentAnnotationsComponent {
void inject(ComponentAnnotationsActivity activity);
// 通过Builder内部接口来定义构造过程
@Component.Builder
interface Builder {
// 与@BindsInstance注解配合使用
@BindsInstance
Builder componentAnnotations(ComponentAnnotations annotations);
ComponentAnnotationsComponent build();
}
}
通过在@Component.Builder注解在内部接口中定义构建的方法,所以不需要通过Module去提供依赖的对象:
public class ComponentAnnotationsActivity extends AppCompatActivity {
@Inject
ComponentAnnotations mComponentAnnotations;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_component_annotations);
// 构造过程中在componentAnnotations方法中传入ComponentAnnotations对象,即可获得注入的对象
DaggerComponentAnnotationsComponent.builder()
.componentAnnotations(new ComponentAnnotations())
.build()
.inject(this);
mComponentAnnotations.log();
}
}
关于@Component.Builder的构建过程
老规矩还是从DaggerComponentAnnotationsComponent类看起:
public final class DaggerComponentAnnotationsComponent implements ComponentAnnotationsComponent {
private final ComponentAnnotations componentAnnotations;
private DaggerComponentAnnotationsComponent(ComponentAnnotations componentAnnotationsParam) {
this.componentAnnotations = componentAnnotationsParam;
}
// 建立连接
@Override
public void inject(ComponentAnnotationsActivity activity) {
injectComponentAnnotationsActivity(activity);
}
// 调用ComponentAnnotationsActivity_MembersInjector的injectMComponentAnnotations方法将ComponentAnnotationsActivity和componentAnnotations对象传入
private ComponentAnnotationsActivity injectComponentAnnotationsActivity(ComponentAnnotationsActivity instance) {
ComponentAnnotationsActivity_MembersInjector.injectMComponentAnnotations(instance, componentAnnotations);
return instance;
}
// 创建Builder对象
public static ComponentAnnotationsComponent.Builder builder() {
return new Builder();
}
// 实现ComponentAnnotationsComponent.Builder接口,实现对应方法
private static final class Builder implements ComponentAnnotationsComponent.Builder {
private ComponentAnnotations componentAnnotations;
// 要实现的方法,设置ComponentAnnotations
@Override
public Builder componentAnnotations(ComponentAnnotations annotations) {
this.componentAnnotations = Preconditions.checkNotNull(annotations);
return this;
}
// 构建对象,创建DaggerComponentAnnotationsComponent实例
@Override
public ComponentAnnotationsComponent build() {
Preconditions.checkBuilderRequirement(componentAnnotations, ComponentAnnotations.class);
return new DaggerComponentAnnotationsComponent(componentAnnotations);
}
}
}
可以看到ComponentAnnotations是在Builder过程中完成创建的,是由我们主动去传入的,与Module无关。
最终还是会调用ComponentAnnotationsActivity_MembersInjector里的方法完成对象的赋值。
@Component.Factory
@Component.Factory注解是另外一种用于构建注入对象的方式,是用于解决@Component.Builder注解会产生的一些问题,试想一下通过@Component.Builder注解去实现对象的注入需要进行很多配置,这就导致DaggerXXX类在与Activity进行绑定的过程中会出现很长的链式调用还容易造成遗漏,进而导致编译错误,而@Component.Factory注解就可以解决这个问题。
那么@Component.Factory注解如何来实现呢?
@Component
public interface ComponentAnnotationsFactoryComponent {
void inject(ComponentAnnotationsFactoryActivity activity);
// 通过@Component.Factory注解定义
@Component.Factory
interface Factory {
// 工厂接口中只能含有一个方法
ComponentAnnotationsFactoryComponent create(@BindsInstance ComponentAnnotationsFactory factory);
}
}
需要遵守的规则:
- 工厂中只能含有1种方法。如果需要绑定许多依赖项,那么不是为每个依赖项创建方法(就像我们对@ Component.Builder所做的那样),只需为每个依赖项添加一个新参数。
- 方法必须返回Component的类型或Component的父类型。
在Activity中进行引用:
public class ComponentAnnotationsFactoryActivity extends AppCompatActivity {
@Inject
ComponentAnnotationsFactory mComponentAnnotationsFactory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_component_annotations_factory);
// 实现factory()方法之后,实现定义好的方法,将所有参数都传入进去,最终和Activity建立连接
DaggerComponentAnnotationsFactoryComponent
.factory()
.create(new ComponentAnnotationsFactory())
.inject(this);
mComponentAnnotationsFactory.log();
}
}
这样就完成一个对象的注入,和Builder不同的是Factory是通过一个方法将多个对象进行注入,提升代码的维护性。
关于@Component.Factory的构建过程
从DaggerComponentAnnotationsFactoryComponent类看起:
public final class DaggerComponentAnnotationsFactoryComponent implements ComponentAnnotationsFactoryComponent {
private final ComponentAnnotationsFactory factory;
private DaggerComponentAnnotationsFactoryComponent(ComponentAnnotationsFactory factoryParam) {
this.factory = factoryParam;
}
// factory方法创建一个Factory对象
public static ComponentAnnotationsFactoryComponent.Factory factory() {
return new Factory();
}
// 与Activity建立联系
@Override
public void inject(ComponentAnnotationsFactoryActivity activity) {
injectComponentAnnotationsFactoryActivity(activity);
}
private ComponentAnnotationsFactoryActivity injectComponentAnnotationsFactoryActivity(
ComponentAnnotationsFactoryActivity instance) {
ComponentAnnotationsFactoryActivity_MembersInjector.injectMComponentAnnotationsFactory(instance, factory);
return instance;
}
// Factory内部类
private static final class Factory implements ComponentAnnotationsFactoryComponent.Factory {
// 用于构建对象的方法,也是我们Component中所定义的
@Override
public ComponentAnnotationsFactoryComponent create(ComponentAnnotationsFactory factory) {
Preconditions.checkNotNull(factory);
return new DaggerComponentAnnotationsFactoryComponent(factory);
}
}
}
在DaggerComponentAnnotationsFactoryComponent中我们可以看到通过Factory内部类中的我们所定义的方法实现了对象的赋值,完成依赖注入的工作。
最终还是会调用ComponentAnnotationsFactoryActivity_MembersInjector里的方法完成对象的赋值。
关于dependencies参数
dependencies参数用于指定所依赖的其它Component,来直接获取对象,来达到Component的分离。
举个老师和学生的例子,老师类是学生类的参数:
public class Teacher {
public void log() {
Log.d("Dagger测试", "获取到Teacher对象");
}
}
public class Student {
private Teacher mTeacher;
public Student(Teacher teacher) {
mTeacher = teacher;
}
public void log() {
Log.d("Dagger测试", "获取到Student对象");
}
}
然后实现各自的Module:
@Module
public class StudentModule {
@Provides
Student providerChild(Teacher teacher) {
return new Student(teacher);
}
}
@Module
public class TeacherModule {
@Provides
Teacher providerParent() {
return new Teacher();
}
}
要注意这里的两个Module没有相互之间的依赖关系,我们会在Component中去实现这些:
// 这里就要使用到我们的dependencies属性了,依赖TeacherComponent
@Component(modules = StudentModule.class, dependencies = TeacherComponent.class)
public interface StudentComponent {
void inject(ComponentAnnotationsActivity activity);
}
设置TeacherComponent,定义所提供的对象Teacher
@Component(modules = TeacherModule.class)
public interface TeacherComponent {
Teacher teacher();
}
在Activity中进行引用:
public class ComponentAnnotationsActivity extends AppCompatActivity {
@Inject
Teacher mTeacher;
@Inject
Student mStudent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_component_annotations);
// 在构建的过程中需要去实现teacherComponent方法进而是两个Component建立起联系
DaggerStudentComponent.builder()
.teacherComponent(DaggerTeacherComponent.create())
.build()
.inject(this);
mTeacher.log();
mStudent.log();
}
}
这种方式可以将原本耦合的Component进行拆分,根据不同的等级来进行划分,具体怎么实现的就不一一看啦,自己去研究一下哦。
@BindsInstance
配合@Component.Builder和@Component.Factory注解的使用
@Subcomponent
实现方式
@Subcomponent注解就比较有意思了,它可以实现和dependencies参数一样的效果,只是他们的实现方式不太一样,通过dependencies参数实现的继承关系,会将构造过程暴露出来,而@Subcomponent注解实现的继承不会暴露构造过程,只是相对复杂一点。
使用@Subcomponent注解还要用到@Module注解中的subcomponent属性来完成依赖。
首先来创建两个实体类Child和Parent,其中Child需要Parent作为参数:
public class Child {
private Parent mParent;
public Child(Parent parent) {
mParent = parent;
}
public void log() {
Log.d("Dagger测试", "获取到Child对象");
}
}
public class Parent {
public void log() {
Log.d("Dagger测试", "获取到Parent对象");
}
}
我们要Activity中进行Child和Parent的依赖,所以要来实现相应的Module和Component,首先先来实现Child的相关方法:
@Module
public class ChildModule {
// 作为参数的Parent将有父Component提供
@Provides
Child providerChild(Parent parent) {
return new Child(parent);
}
}
// 使用@Subcomponent,指定对应的模块
@Subcomponent(modules = ChildModule.class)
public interface ChildComponent {
void inject(DependenciesActivity activity);
@Subcomponent.Builder
interface Builder {
ChildComponent build();
}
}
实现了Child的相关类,和一般的Component方式还是比较相似的,接着来实现Parent的相关类:
// 在@Module注解中指定subcomponents,相当于该Module所提供的对象都是能够在ChildComponent所关联的Module中获取的
@Module(subcomponents = ChildComponent.class)
public class ParentModule {
@Provides
Parent providerParent() {
return new Parent();
}
}
@Component(modules = ParentModule.class)
public interface ParentComponent {
// 与ChildComponent建立联系
ChildComponent.Builder buildChildComponent();
}
然后在Activity中进行调用:
public class DependenciesActivity extends AppCompatActivity {
@Inject
Parent mParent;
@Inject
Child mChild;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dependencies);
DaggerParentComponent
.create() // 创建了ParentComponent
.buildChildComponent() // 与ChildComponent建立起联系
.build() // 构造
.inject(this); // 与Activity建立起联系
mParent.log();
mChild.log();
}
}
这种方式和dependencies参数的实现方式最大区别在于父与子Component建立起联系的过程是否暴露在Activity中,下面我们来看看@Subcomponent注解背后的实现过程吧。
源码分析
Subcomponent的源码看上去和Component还是很像,除了没有dependencies参数,说明它们两者的使用还是十分相近的。
@Retention(RUNTIME)
@Target(TYPE)
@Documented
public @interface Subcomponent {
Class<?>[] modules() default {};
@Retention(RUNTIME)
@Target(TYPE)
@Documented
@interface Builder {}
@Retention(RUNTIME)
@Target(TYPE)
@Documented
@interface Factory {}
}
构造过程
关于使用Subcomponent构造出来依赖还是很有趣的来看一下实现过程吧:
public final class DaggerParentComponent implements ParentComponent {
private final ParentModule parentModule;
private DaggerParentComponent(ParentModule parentModuleParam) {
this.parentModule = parentModuleParam;
}
public static Builder builder() {
return new Builder();
}
// 优先构建完成本类的对象
public static ParentComponent create() {
return new Builder().build();
}
// 进行子类Component的配置将父类的对象提供给子类作为参数
@Override
public ChildComponent.Builder buildChildComponent() {
return new ChildComponentBuilder();
}
// 父类的内部类
public static final class Builder {
private ParentModule parentModule;
private Builder() {
}
public Builder parentModule(ParentModule parentModule) {
this.parentModule = Preconditions.checkNotNull(parentModule);
return this;
}
public ParentComponent build() {
if (parentModule == null) {
this.parentModule = new ParentModule();
}
return new DaggerParentComponent(parentModule);
}
}
// 子类的内部类,实现子类Component定义的接口
private final class ChildComponentBuilder implements ChildComponent.Builder {
@Override
public ChildComponent build() {
return new ChildComponentImpl(new ChildModule());
}
}
// 子类的具体实现逻辑
private final class ChildComponentImpl implements ChildComponent {
private final ChildModule childModule;
private ChildComponentImpl(ChildModule childModuleParam) {
this.childModule = childModuleParam;
}
private Child getChild() {
return ChildModule_ProviderChildFactory.providerChild(childModule, ParentModule_ProviderParentFactory.providerParent(DaggerParentComponent.this.parentModule));
}
// 最终调用inject方法与Activity建立起联系
@Override
public void inject(SubComponentActivity activity) {
injectSubComponentActivity(activity);
}
private SubComponentActivity injectSubComponentActivity(SubComponentActivity instance) {
SubComponentActivity_MembersInjector.injectMParent(instance, ParentModule_ProviderParentFactory.providerParent(DaggerParentComponent.this.parentModule));
SubComponentActivity_MembersInjector.injectMChild(instance, getChild());
return instance;
}
}
}
通过@Subcomponent注解实现的构建过程,将所有的逻辑都封装到了父类的Dagger生成类中去处理,这也是和使用dependencies属性进行构建的很大的一个区别,但是通过@Subcomponent注解实现构建过程封装在了生成类中而没有向外暴露,也更容易进行维护。
网友评论