美文网首页Android学习
04.对注解的分类讲解——Component部分

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

作者: redrain39 | 来源:发表于2020-01-09 09:02 被阅读0次

    关于Dagger2

    前言

    本文将通过对注解的分类讲解来交代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部分

        本文链接:https://www.haomeiwen.com/subject/qfaeactx.html