04.对注解的分类讲解——Component部分

关于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注解实现构建过程封装在了生成类中而没有向外暴露,也更容易进行维护。

你可能感兴趣的:(04.对注解的分类讲解——Component部分)