Dagger2教程六之Component的组织方法(原)

Dagger2教程六之Component的组织方法(原)为了介绍 Dagger2 的使用 我们搭建了一个 Demo 来逐步分析 大家可以在这里下载源码 这个源码与之前的五个小节源码不同 https github com dushaofeng DaggerDemo2 git nbsp nbsp nbsp nbsp 上一节我们介绍了 Dagger2 教程五之单例模式 这一节我们来介绍 Component 的组织方法 nbsp nbsp nbsp nbsp 所谓 Component 组织方法 也就是我们工

        为了介绍Dagger2的使用,我们搭建了一个Demo来逐步分析,大家可以在 这里下载源码(
这个源码与之前的五个小节源码不同)(https://github.com/dushaofeng/DaggerDemo2.git)。

        上一节我们介绍了 《Dagger2教程五之单例模式》,这一节我们来介绍Component的组织方法。
        所谓Component组织方法,也就是我们工程中的Component该如何分布和结合。
        对于一款APP来说,一些基础的服务类比如全局Log、图片加载器、网络请求器、缓存器等应该做到全局单例,而对某个Activity或者Fragment来说又有自己的单例或者非单例的对象,那么这种情况下该如何组织我们的注入结构呢?
        我们现在知道Component是连接注入类和目标类的桥梁,那么最简单的结构应该是这样的:
        1、Application负责创建全局的单例或者非单例注入类的Component对象
        2、Activity或Fragment在继承Application提供的Component基础上扩展自己的Component接口




        那么具体该如何操作呢?
        Dagger2给我们提供两种方法来实现注入继承。

一、使用dependencies属性实现继承注入

        如果对比源码看的话, 请将源码分支切换到UseDependencies分支

1.1、准备ApplicationBean对象

        我们创建一个ApplicationBean对象用来作为目标类,准备将其注入到应用中:

 public class ApplicationBean { private String name = null; public ApplicationBean() { name = "AppBean"; } public String getAppBeanName() { return name; } }

1.2、准备APP级别的Module对象

        然后创建ApplicationModule用来将其注入到目标类,并且我们标记了Singleton准备将其作为单例模式注入:

 @Module public class ApplicationModule { //作为单例模式注入app @Singleton @Provides ApplicationBean privoderAppBean() { return new ApplicationBean(); } }

1.3、准备APP级别的Component对象

        相应的,我们创建ApplicationComponent用来连接ApplicationModule和Application:

 @Singleton @Component(modules = ApplicationModule.class) public interface ApplicationComponent { void inject(DaggerApplication application); //说明将BeanForApplication开放给其他Component使用 ApplicationBean providerAppBean(); }

        在这里请注意两点:
        1、由于我们设计要将ApplicationBean作为单例注入,因此ApplicationComponent也需要标记@Singleton标识
        2、我们在ApplicationComponent中提供了一个返回值为ApplicationBean对象的方法声明, 它的作用是将该Component中的ApplicationBean对象暴露给其他Component使用,相当于AIDL语言中的方法声明

1.4、注入Application

        我们需要在Application中完成两个任务:
        1、将ApplicationBean注入到Application内部
        2、将ApplicationComponent对象共享给Activity或者其他类
        具体实现如下:

 public class DaggerApplication extends Application { private ApplicationComponent mAppComponent; @Inject ApplicationBean mAppBean1; @Inject ApplicationBean mAppBean2; @Override public void onCreate() { super.onCreate(); if (mAppComponent == null) { mAppComponent = DaggerApplicationComponent.create(); } mAppComponent.inject(this); Log.d("Dagger", "Application mAppBean1:" + mAppBean1); Log.d("Dagger", "Application mAppBean2:" + mAppBean2); } public ApplicationComponent getAppComponent() { return mAppComponent; } }

        在这里我们注入了两次ApplicationBean对象,并在注入完成后打印出它们的地址用于观察是否实现了单例的功能。

1.5、准备ActivityBean对象

        我们再创建一个Activity的Bean对象用于观察注入情况:

 public class ActivityBean { private String name = null; public ActivityBean() { } public String getAppBeanName() { return name; } }

1.6、准备Activity的Module对象

        Activity的Module应该提供ActivityBean的注入方式:

 @Module public class ActivityModule { @Provides ActivityBean providerActivityBean() { return new ActivityBean(); } }

1.7、准备Activity的Component对象

        我们要在Activity的Component中继承ApplicationComponent,也就是要 让Activity的Component不仅可以从ActivityModule中查找注入类,还要能从ApplicationModule中查找到注入类

 @ForActivity @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity activity); void inject(MainActivity.OtherClass otherClass); }

        这个Component的写法有三处与之前的写法不同的地方:
        1、添加了ForActivity的修饰,而这个ForActivity就是我们自定义的Scope的一种,根据之前我们的介绍, 他的作用和Singleton是一样的,用于限制该Component的使用范围:

 @Scope @Retention(RUNTIME) public @interface ForActivity { }

        为什么要添加这个修饰呢?因为当前Component所继承的ApplicationComponent中包含Singleton的注释, 所以ApplicationComponent的子类Component的作用范围不能高于ApplicationComponent的作用范围,因此需要对ActivityComponent也添加Scope的限定。
        2、Component中多了”dependencies = ApplicationComponent.class”的注释,它的作用就是告诉Dagger, 当前Component依赖于ApplicationComponent,在查找注入类的时候不仅要在ActivityModule中查找,还需要去ApplicationComponent中的Module中查找。
        3、我们提供了两个inject()方法,作用是要将该Component同时注入到两个对象中,这在之前的介绍中使用过。

1.8、设计Activity对象

        我们接下来就要在Activity中同时注入ActivityBean和ApplicationBean对象了,并且ApplicationBean还是全局单例的模式,为了扩展测试,我们在Activity中还创建了一个OtherClass,也将ActivityBean和ApplicationComponent都注入进去进行观察:

 public class MainActivity extends AppCompatActivity { @Inject ApplicationBean applicationBean1; @Inject ApplicationBean applicationBean2; @Inject ActivityBean activityBean; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerApplication application = (DaggerApplication) getApplication(); ApplicationComponent applicationComponent = application.getAppComponent(); ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build(); activityComponent.inject(this); Log.d("Dagger", "Activity activityBean:" + activityBean); Log.d("Dagger", "Activity applicationBean1:" + applicationBean1); Log.d("Dagger", "Activity applicationBean2:" + applicationBean2); OtherClass otherClass = new OtherClass(); } class OtherClass { @Inject ApplicationBean applicationBean1; @Inject ApplicationBean applicationBean2; @Inject ActivityBean activityBean; public OtherClass() { DaggerApplication application = (DaggerApplication) getApplication(); ApplicationComponent applicationComponent = application.getAppComponent(); ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build(); activityComponent.inject(this); Log.d("Dagger", "OtherClass activityBean:" + this.activityBean); Log.d("Dagger", "OtherClass applicationBean1:" + this.applicationBean1); Log.d("Dagger", "OtherClass applicationBean2:" + this.applicationBean2); } } }

1.9、结果分析

        我们运行之后打印出来的Log如下图:
         Dagger2教程六之Component的组织方法(原)
        我们来分析Log的表现:
        1、Application中注入的mAppBean1和mAppBean2以及Activity中注入的applicationBean1、applicationBean2还有OtherClass中注入的applicationBean1、applicationBean2这六个对象的地址都是95c5354
        分析:
            1、在Activity和OtherClass中我们可以获取到ApplicationBean对象,说明我们当前的注入方式完成了”Activity从Application继承Component进行注入”的任务
            2、我们不仅在APP的全局都获取到了ApplicationBean对象,而且得到的都是单例对象,这说明我们在ApplicationModule中对ApplicationBean进行单例注入的方式在全局都是有效的
        2、Activity中的activityBean和OtherClass中的activityBean对象地址不同
        分析:
            ActivityBean对象在Activity中和OtherClass中分别注入了两次,所以这两次注入是独立的,它们注入的ActivityBean对象是不同的
        至此,该注入方式我们就介绍完毕,下面我们来介绍另一种继承的方式。

二、使用Subcomponent的方式进行继承注入

        如果对比源码看的话, 请将源码分支切换到UseSubcomponent分支

2.1、如何注入

        该方式和上面的方式区别之处只有三个地方:

1、改造Activity的Component对象

        我们需要先来改造Activity的Component对象,也就是ActivityComponent,需要将其改写为如下的方式:

        @ForActivity
        @Subcomponent(modules = ActivityModule.class)
        public interface ActivityComponent {
            void inject(MainActivity activity);


            void inject(MainActivity.OtherClass otherClass);
        }

        它与之前的方式的区别有两点:
        1、不再使用@Component而使用@Subcomponent来注释
        2、删除了”dependencies = ApplicationComponent.class”语句


2、改造Application的Component对象

        然后我们来改造Application的Component对象也就是ApplicationComponent,将其改造成如下方式:

        @Singleton
        @Component(modules = ApplicationModule.class)
        public interface ApplicationComponent {
            //注入DaggerApplication
            void inject(DaggerApplication application);


            //说明将BeanForApplication开放给其他Component使用
            ApplicationBean providerAppBean();


            ActivityComponent activityComponent();
        }

        这里的改造只是多了一句声明:ActivityComponent activityComponent()

3、改造Activity中的注入方式

        我们还需要改造Activity和OtherClass中的注入方式,改造成如下方式(Activity和OtherClass的注入方式相同):

            DaggerApplication application = (DaggerApplication) getApplication();
            ApplicationComponent applicationComponent = application.getAppComponent();
            applicationComponent.activityComponent().inject(this);

        然后就完成了所有改造,运行结果如下:
         Dagger2教程六之Component的组织方法(原)
        这个结果与dependencies的方式结果是一致的,说明两种注入方式都达到了Component继承的目的。

三、dependencies与Subcomponent注入方式的区别

        这两种方式的区别其实在Activity注入时就可以看出来,我们再次贴出它们的对比:
        dependencies方式:

            DaggerApplication application = (DaggerApplication) getApplication();
            //获取ApplicationComponent对象
            ApplicationComponent applicationComponent = application.getAppComponent();
            //用ActivityComponent对象进行注入
            ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build();
            activityComponent.inject(this);

        Subcomponent方式:

            DaggerApplication application = (DaggerApplication) getApplication();
            ApplicationComponent applicationComponent = application.getAppComponent();
            //用ApplicationComponent对象进行注入
            applicationComponent.activityComponent().inject(this);

        结果发现,dependencies方式中,我们最终调用的是ActivityComponent对象中的inject()方法,而Subcomponent方式中,我们最终调用的是ApplicationComponent的inject()方法。
        从Component的注释上我们也可以看到这个区别:
        dependencies方式:

            //ApplicationComponent
            @Component(modules = ApplicationModule.class)
            public interface ApplicationComponent {
                ......
            }


            //ActivityComponent 
            @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
            public interface ActivityComponent {
                ......
            }

        Subcomponent方式:

            //ApplicationComponent
            @Component(modules = ApplicationModule.class)
            public interface ApplicationComponent {
                ......
                ActivityComponent activityComponent();
            }
            
            //ActivityComponent
            @Subcomponent(modules = ActivityModule.class)
            public interface ActivityComponent {
                ......
            }

        对比中我们发现, dependencies中Component强调的是在子类Component依赖于某个Component(子类为主角),而Subcomponent中强调的则是在父类Component中提供某个子类的Component(父类为主角)

四、如何选择两种继承方式

        那么该如何选择这两种继承方式呢?
        在Stackoverflow中就有人提出了这样的问题(http://stackoverflow.com/questions/29587130/dagger-2-subcomponents-vs-component-dependencies),简单理解就是:
        dependencies方式让Component之间更加独立,结构更加清晰,也更利于解耦。
        所以该如何选择是否已经有了答案呢?

        至此,Dagger2系列介绍就全部结束,下课。

        我们再次列出本系列所有的总结:

        《Dagger2教程一之配置(原)》

        《Dagger2教程二之基础使用(原)》

        《Dagger2教程三之构造方法带参数的情况(原)》

        《Dagger2教程四之多构造方法的情况(原)》

        《Dagger2教程五之单例模式(原)》






























































































































版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222739.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午3:05
下一篇 2026年3月17日 下午3:05


相关推荐

  • p2p流媒体技术(简述流媒体的特点)

    【前言】今天发现二哥在搞流媒体,顿时来了兴趣(之前在考试维护的时候经常听老师说P2P等),追问之下之前林哥搞成功过,而且写了一系列博客;于是乎便翻开博客,认真看了看,写的非常不错:从概念到安装实现(linux和windows)再到性能测试对比非常不错(详见:http://blog.csdn.net/u012407484/article/category/2732453);…

    2022年4月18日
    94
  • Hadoop实战_hadoop 项目实战

    Hadoop实战_hadoop 项目实战hadoop实战练习(二)引言:哈哈,时隔几日,坏蛋哥又回来了,继上一篇hadoop实战练习(一),坏蛋哥准备继续写一个实战练习实例。苏格拉底曾说:所有科学都源于需求。那么我们就抛出今天实战项目的需求:百度采集了一段时间用户的访问日志。需要将数据进行清洗变成结构化的数据,方便后面模型或报表的制作。那么就让我们开始吧!码字不易,如果大家想持续获得大数据相关内容,请关注和点赞坏蛋哥(haha…)文章目录:文章目录hadoop实战练习(二)一项目需求分析二项目实现思路三具体实现代码讲解

    2025年6月7日
    5
  • tez详解

    tez详解1tez 的概览 1 1tez 介绍 1 1 1 介绍 tez 是一个 apache 的开源项目 意在构建一个应用框架 能通过复杂任务的 DAG 来处理数据 它是基于当前的 hadoopyarn 之上 换句话就是 yarn 为其提供资源 tez 主要的两个设计目标 增强终端用户使用 灵活的数据流定义 API 灵活的输入输出运行时模型 强调处理模型 数据类型无关简洁部署高性能执行 通过 mapreduce 提

    2026年3月19日
    1
  • 在国内怎么用netflix(netflix为什么在中国用不了)

    SpringClound和SpringBoot集成时Idea报错:Cannotresolveorg.springframework.cloud:spring-cloud-starter-netflix-eureka-server:unknown原因分析:找不到依赖的jar包查看配置的依赖SpringBoot的版本:2.0.7.RELEASESpringCloud的版本:Finchley.RC1它们不匹配造成异常解决方案:更改SpringCloud的版本为Finch

    2022年4月13日
    172
  • MyEclipse10安装SVN插件的几种方法

    MyEclipse10安装SVN插件的几种方法方法一:直接解压下载SVN插件:site-1.6.18.ziphttps://github.com/subclipse/subclipse解压后将features文件和plugins文件拷贝至:D:\MyEclipse\MyEclipse10\dropins(MyEclipse的安装目录)重启MyEclipse即可出现SVN!方法二:在线安装打开HELP->MyEclipseConfi

    2022年7月21日
    13
  • 数据库拉链表详解_拉链表断链

    数据库拉链表详解_拉链表断链一、前言在上一节简单介绍了拉链表,本节主要讲解如何通过binlog采集MySQL的数据并且按月分区的方式实现拉链表。这里以上节介绍的用户表(user)举例二、涉及到的表1.原始表(user)原始表指的是MySQL中的表,表结构如下:其中name为主键,如果没有主键则无法做拉链表。2.binlog流水表(user_binlog)操作类型字段枚举值为:insert、update、delete。设…

    2022年10月17日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号