美文网首页技术干货儿AndroidAndroid Testing
Android:dagger2让你爱不释手-基础依赖注入框架篇

Android:dagger2让你爱不释手-基础依赖注入框架篇

作者: 牛晓伟 | 来源:发表于2016-03-16 07:41 被阅读82427次

    前言

    dagger2的大名我想大家都已经很熟了,它是解决Android或java中依赖注入的一个类库(DI类库)。当我看到一些开源的项目在使用dagger2时,我也有种匆匆欲动的感觉,因此就立马想一探它的究竟,到底能给我带来怎样的好处。在学习使用dagger2的过程中,我遇到了以下的一些困惑:

    • dagger2中的Inject,Component,Module,Provides等等都是什么东东,有什么作用?
    • dagger2到底能带来哪些好处?
    • 怎样把dagger2应用到具体项目中?

    在具体学习dagger2的时候,看了好多博客,看的时候感觉挺简单的,但是在真正使用到项目中时候,脑袋就懵了,无从下手,Component应该怎么用,能放些什么方法? Module应该放些啥内容?Scope怎么起到作用域控制?.....各种疑问就横空而出。所以也许会有正在学习或即将要使用dagger2的同学在使用过程中遇到和我一样的困惑,因此我决定把我对dagger2的理解、使用经验分享给大家,希望能对大家有帮助。
    我会分几节给讲解dagger2。

    本节内容

    Inject,Component,Module,Provides它们是什么?怎么去理解它们?各自有什么作用?主要从抽象的概念讲解,不会涉及到具体代码的剖析。

    提前科普知识点

    在讲解之前,我希望大家对以下知识点有所了解(知道的同学可以跳过)

    • 依赖注入(Dependency Injection简称DI)
    • java中注解(Annotation)

    依赖注入:就是目标类(目标类需要进行依赖初始化的类,下面都会用目标类一词来指代)中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建,而是通过技术手段可以把其他的类的已经初始化好的实例自动注入到目标类中。

    di.png
    若您还是对依赖注入不了解,点击我可以让您了解更多
    dagger2就是实现依赖注入的一种技术手段

    其次java注解的概念用法我们就不讲了,dagger2中核心点就是java注解,点击我可以了解更多java注解知识

    正式开始

    以下的内容我会尝试着去模仿dagger2的作者是怎样一步步完成dagger2这样伟大的依赖注入类库的场景来讲解(首先这个场景是我意淫的,大家勿喷,模仿该场景主要目的是为了能由简到难一步步更深入的了解dagger2)

    Inject是什么鬼

    先看一段代码:

     class A{
           B b = new B(...);
           C c = new C();
           D d = new D(new E());
           F f = new F(.....);
     }
    

    上面的代码完全没任何问题,但是总感觉创建对象的这些代码基本都是重复的体力劳动,那何尝不想个办法,把这些重复的体力劳动用一种自动化的、更省力的方法解决掉,这样就可以让开发的效率提高,可以把精力集中在重要的业务上了。

    我们可以用注解(Annotation)来标注目标类中所依赖的其他类,同样用注解来标注所依赖的其他类的构造函数,那注解的名字就叫Inject

       class A{
            @Inject
            B b;
       }
    
       class B{
           @Inject
           B(){
           }
       }
    

    这样我们就可以让目标类中所依赖的其他类与其他类的构造函数之间有了一种无形的联系。但是要想使它们之间产生直接的关系,还得需要一个桥梁来把它们之间连接起来。那这个桥梁就是Component了。


    Inject.png

    Component又是什么鬼
    Component也是一个注解类,一个类要想是Component,必须用Component注解来标注该类,并且该类是接口或抽象类。我们不讨论具体类的代码,我想从抽象概念的角度来讨论Component。上文中提到Component在目标类中所依赖的其他类与其他类的构造函数之间可以起到一个桥梁的作用。
    那我们看看这桥梁是怎么工作的:
    Component需要引用到目标类的实例,Component会查找目标类中用Inject注解标注的属性,查找到相应的属性后会接着查找该属性对应的用Inject标注的构造函数(这时候就发生联系了),剩下的工作就是初始化该属性的实例并把实例进行赋值。因此我们也可以给Component叫另外一个名字注入器(Injector)

    component.png
    小结下
    目标类想要初始化自己依赖的其他类:
    • 用Inject注解标注目标类中其他类
    • 用Inject注解标注其他类的构造函数
    • 若其他类还依赖于其他的类,则重复进行上面2个步骤
    • 调用Component(注入器)的injectXXX(Object)方法开始注入(injectXXX方法名字是官方推荐的名字,以inject开始)

    Component现在是一个注入器,就像注射器一样,Component会把目标类依赖的实例注入到目标类中,来初始化目标类中的依赖。

    为啥又造出个Module

    现在有个新问题:项目中使用到了第三方的类库,第三方类库又不能修改,所以根本不可能把Inject注解加入这些类中,这时我们的Inject就失效了。

    那我们可以封装第三方的类库,封装的代码怎么管理呢,总不能让这些封装的代码散落在项目中的任何地方,总得有个好的管理机制,那Module就可以担当此任。
    可以把封装第三方类库的代码放入Module中,像下面的例子:

        @Module
        public class ModuleClass{
              //A是第三方类库中的一个类
              A provideA(){
                   return A();
              }
        }
    

    Module其实是一个简单工厂模式,Module里面的方法基本都是创建类实例的方法。接下来问题来了,因为Component是注入器(Injector),我们怎么能让Component与Module有联系呢?

    Component的新职责

    Component是注入器,它一端连接目标类,另一端连接目标类依赖实例,它把目标类依赖实例注入到目标类中。上文中的Module是一个提供类实例的类,所以Module应该是属于Component的实例端的(连接各种目标类依赖实例的端),Component的新职责就是管理好Module,Component中的modules属性可以把Module加入Component,modules可以加入多个Module。

    Component_桥梁概念.png

    那接下来的问题是怎么把Module中的各种创建类的实例方法与目标类中的用Inject注解标注的依赖产生关联,那Provides注解就该登场了。

    Provides最终解决第三方类库依赖注入问题

    Module中的创建类实例方法用Provides进行标注,Component在搜索到目标类中用Inject注解标注的属性后,Component就会去Module中去查找用Provides标注的对应的创建类实例方法,这样就可以解决第三方类库用dagger2实现依赖注入了。

    总结

    Inject,Component,Module,Provides是dagger2中的最基础最核心的知识点。奠定了dagger2的整个依赖注入框架

    • Inject主要是用来标注目标类的依赖和依赖的构造函数
    • Component它是一个桥梁,一端是目标类,另一端是目标类所依赖类的实例,它也是注入器(Injector)负责把目标类所依赖类的实例注入到目标类中,同时它也管理Module。
    • Module和Provides是为解决第三方类库而生的,Module是一个简单工厂模式,Module可以包含创建类实例的方法,这些方法用Provides来标注
    component_module_inject.png
    希望能帮您更好的理解dagger2。
    Android:dagger2让你爱不释手-重点概念讲解、融合篇

    个人简介
    本人是一名android开发工程师,开发android多年,若有志同道合的朋友想联系我,可以加我的:qq/微信: 704451290

    欢迎各位多多交流,转载请标明出处。
    本人微信:704451290

    本人公众账号

    相关文章

      网友评论

      • 大鱼_BigFish1:真是豁然开朗啊,谢谢作者
      • ef9ecb1ca745:非常棒,谢谢作者,通俗易懂。:relaxed:
      • 二少2017:看了这么多,终于找到一个能看懂的,very good
      • BUG君:请教一个问题,dagger2是apt的但是为什么它的注解类型都是RUNTIME类型的呢??不是矛盾吗?
        BUG君:@牛晓伟 应该是CLASS类型的,为什么用RUNTIME类型的
        牛晓伟:@BUG君 怎么矛盾了
      • channelRead0:通俗易懂
      • 紫霞狼_ae2d:简书应该给你广告费,写得很好,终于有点懂了,特意注册来顶贴 :)
      • 1琥珀川1:2018-6-5学习
      • 932bbd0799f6:我看了 好多篇dagger2 作者 这篇 讲的最好!!! 强力给赞
      • 温暖了流年:本文的作者把握住了Dagger作者的脉搏
      • hayabusa_l:用设计者的角度 为新手讲解,非常棒
      • 0e37276edafc:讲的太棒了,通俗易懂,比其它文章更让我容易接受,我大概明白点了,能再来一个例子就完美了!
      • 阿V很简单:原谅我,我从去年开始看了也写了demo,但始终没有十分掌握,因此也没有正式运用到项目中去,到今天我终于终于看懂了原理,真想大呼一声‘爽’:smile:
      • zhezi521:Dagger 2 看这三篇 就足够了。。。真诚感谢
      • bf997ddd485d:简洁明了清晰
      • 荒漠捕食者:这是宇宙诞生以来,我点赞的第一个dragger2讲解教程
      • ZKTiannnnnnnnnn:赞,讲的最明白的一篇
      • f111570cda18:真的是通俗易懂~:+1:
      • 凸图土吐:是不是只能 注入一次呢?
        我尝试注入两次失败了
        我是这样设计的 基类Activity有一个ActivityComponent注入
        然后在子类中 有一个HttpComponent的注入
        然后报错了
        我是想Http组件 是不是应该跟ActivityComponent 应该区分开来 所以想着注入两次
        那如果只能注入一次 那是不是我的某个组件得依赖其它组件 就如现在HttpComponent依赖ActivityComponent 这样我才即能有HttpComponent的功能 又有ActivityComponent 的功能
        但是这样又违背设计了 因为HttpComponent和ActivityComponent 不相互依赖吧
      • 孤独狂饮:文章确实不错哈,入门了解的很清楚。
      • 黑白咖:签到
      • Myy_Fish:写得不错,第一次就看懂了。但是没有实践实例来验证有点可惜
      • BrokenDust:好像看懂了一点
      • d5bd132e85f5:谢谢大佬,超喜欢大佬的文章,浅显易懂。
      • 3b5a63689539:我艹!文章思路清晰,简单易懂...看了别人的都是一脸懵逼...看了你的...不知道怎么形容 - -!送你俩字.牛`13...
      • 天门一只猿:说实话 ,你讲的真心好。我看了大半天了,都没讲清楚个所以然,看了这篇,才明白个道理。真赞
      • 28068cf14721:思路很清晰,很容易理解。
        牛晓伟:@风向标_5521 多谢
      • 凄惨红:看了几篇关于dagger2的文章了,始终觉得dagger2然并卵啊,感觉只适合大型项目解耦,毕竟它只能去除构造器所造成的耦合(这么理解有错吗?)。而且我有几个疑问,1:一般你们在项目中使用时是否只写一个Module和Component?2:如果一个类有 多个构造器,dagger2要如何判断使用哪个?
      • 小火星火小小:如果了解Spring,dagger2的这几个概念就很好理解了
      • UP7CR:您好,将您的dagger系列三篇文章转载到自己的公众号“AndroidEng”,会注明作者及出处,多谢多谢!
      • 6541752045c1:画风如此新奇,一看就是佳作:clap:
      • 梦华芳秋:题主,Component作为目标类和目标类所依赖的类之间的桥梁,这是代理模式?还是什么?求解答!
      • seraphzxz:拨云散雾,赞一个~~:pray:
      • 唯爱_0834:不错不错,学习了!
      • 一起哈啤:赞赞赞,很清晰
      • boboyuwu:请教下楼主哈 为啥构造方法上面可以用Inject不能用Qualifier?
        boboyuwu:@牛晓伟 构造方法用Qualifier就会报错说不能在Inject构造上用Qualifier
        牛晓伟:@boboyuwu 可以用Qualifier
      • jinchen_jianshu:大赞,清晰易懂的文章,666
      • 莫宝咯:刚超了一遍Demo,没懂什么意思,看你的文章看懂了,写的很好,通俗易懂,Good,Thank you
      • boboyuwu:文章写的很棒有个疑问哈
        Component在搜索到目标类中用Inject注解标注的属性后,Component就会去Module中去查找用Provides标注的对应的创建类实例方法,这样就可以解决第三方类库用dagger2实现依赖注入了 这段:
        目标类中发现@inject中标注的成员后去找这个类里面有没有@inject标注,如果找不到(第三方类库,接口等)再去搜索@Module标注的对象, 然后在component中发现inject(中的类是目标类)就创建provide中实例对象注入到目标成员中?这是我理解的流程不知道对不对
      • 17b421864dd7:这个写的真不错,非常适合初学者
      • f590affc50d2:厉害的作者
      • hello2mao:写的太好了,终于看懂了点,多谢
      • 关山明月::+1: 通俗易懂!
      • c25fe4cb884f:牛逼~~~讲的很清楚,好像没有多少代码,不知道自己理解的正不正确,接着看
      • Dinos:感谢博主,感觉突然明朗了许多。=-=
      • 心需要麻醉:目标类 这个词好
      • 小心搬砖:浅显易懂,很容易理解
      • 时间仍在o是我们飞逝:看了评论,我就可以放心的开始阅读了。。。
      • Lostoy007:看了网上好几篇文章,包括dagger官方文档,讲的一塌糊涂,这篇文章思路清晰,把dagger的关系网理的很清,大赞!!!有一点点缺陷是针对每个点再提供点完整的例子就完美了~
      • 碧海鱼龙:看过最通俗易懂的dagger2文章,给赞了!
      • MonkiRayman:我就说,怎么我看的其他文章,他们创建实例对象的方法不一样。看了作者你的才知道,原来存在两种创建
      • 049752ce4854:赞,文章讲解清晰易懂,看了其他几遍文章,moudle,provider,inject,component貌似是翻译过来的,句子都不通顺,完全没表达明白含义,楼主这篇一看便明白,感谢~
      • adonis_lsh:写的很好,不错,浅显易懂
      • 欢乐的乐:看了这么多文章还是从你这里入门了,谢谢你啊,如果有代码就更好了:+1:
        我在这里贴上我看完这篇文章动手打代码的文章吧,方便大家学习。
        http://blog.csdn.net/u012943767/article/details/51897247
      • 54c0d782cb19:讲的很形象,很具体,很好理解,适合初学者,谢谢作者
      • 带心情去旅行:豁然开朗
      • 技术萌新:我们写的一些工具类,adpater,等也需要用这个吗,不是在activty里面调用他们,是在presenter中
        技术萌新:@牛晓伟 能具体说说什么样的类需要用这个吗?
        牛晓伟:@8e9874088039 这些就没必要了
      • 66f27edb1f30:我看了你这个之后还是有点蒙,我使终没有搞明白那个比如DaggerMainActivityComponent.builder()
        .mainActivityModule(new MainActivityModule(this))//其中的这个DaggerMainActivityComponent是怎么来的,而且我在项目当中也没找到这个相关的类
        牛晓伟:@赱丶 这是dagger自动生成的代码,编译一下就有了
      • 平凡至简:楼主如果有结合个小demo来讲解的话,效果可能会更好,期待~
      • 平凡至简:看了N篇关于Dagger2的博文,终于在这里找到了想要的
      • 淼_33:文章写的不错,简单易懂。现在刚入手dagger,很高兴看到这篇文章。
      • 琴瑟迷音:特地注册个帐号 过来评论下:( ఠൠఠ )ノ,我喜欢! :blush:
        牛晓伟: @JiaTao 谢谢
      • 天青色等煙雨_而我在等妳:好文章和差文章就是不一样,好文章一篇顶10篇。我也是看了好多,但是都让我感觉云里雾里的,你这一篇就把我搞明白了。厉害厉害!
      • 看秋叶一片片飘落:dagger2 入门,通俗易懂!
      • ml_bright:楼主讲解的很到位,生动形象
      • DoAndKeep:首次打赏~非常感谢! :kissing_heart:
      • 会理发的店小二:还请楼主多多意淫
      • ping0505:讲的很详细 容易理解 :+1:
      • 85fa5ac033b5:通俗易懂
      • 程序亦非猿:匆匆欲动的感觉
      • 46b1434d316d:赞一个
      • iceman_dev:这写的真的很清晰,
      • 85771860e525:做的新项目用到Dagger2,虽然跟着套路会模仿写,可是完全不理解,看你的文章,有一点理解了,期待续章,very thx!!! :+1:
      • 6ee72519b51d:通俗易懂 好文,看了那么多就你的我看懂了0 0
      • ShiroSora:写得通俗易懂,厉害
      • _ERROR:看了好多好多文章都没懂,看你的一下就理解了~
        但是我还是有个疑问,就是目标类所需要的依赖实例可能是动态的,比如View的点击事件的事件类就是依赖,但他是开发者在创建点击事件的时候直接写的,如果使用Dagger来实现,是要把点击事件分别写很多个类文件,然后在需要点击事件的目标类中InJect吗?
        牛晓伟:@_ERROR 这种动态的dagger应该实现不了,
      • Android解忧杂货店:真心不错!其他的文章天花乱坠将一通好像在堆砌概念!真的要把知识化作自己的语言然后通俗易懂地讲出来才算是理解深刻吧!笔者写得很好!
      • DoAndKeep:通俗易懂,大赞!
      • 2Tu:特意注册来顶贴
        scope解释很好
      • 薄炳鑫:加油
      • 呆瓜酱: :smile: 确实是好文章,棒棒的
      • cb16d862bd0a:讲的非常直白
        感谢
      • 字字珠玑:讲的非常清楚,十分感谢。
      • 2a461069b07f:看了好多dagger的讲解,但这篇才让我看懂,真正的通俗易懂,多谢博主的无私奉献
      • GoodGoodStuday:第一次没怎么看懂,,后来就不看了,,过了一个月,在看,就突然明白了 :smiley:
      • 荒井:多谢。
      • 键盘走过的日子:第一次接触这个,看的不是很懂,不过看大家评论这么好,我有理由再多读几遍。
      • 17c389a4c161:写的好,转载了 :grin:
      • b878dfbf65fc:描述的很好 简单易懂 没接触过相关框架的 也能在读完后有定的了解。赞赞赞
        牛晓伟: @b878dfbf65fc 多谢
      • Champion是冠军:细节比较少
      • lipeiyan:如沐春风啊
      • GoodGoodStuday:晓伟哥,你好。。今天又重温了一下你的文章,,上文提出Component 没有用具体的代码做讨论,,只用接口或抽象,,,如果是具体的代码呢。。
        牛晓伟: @小宝拜财神 好的
        GoodGoodStuday:@牛晓伟 嗯知道了,晓伟哥。。不过能再结合你写的demo,讲解一下,能让人读着更酣畅淋漓 :smile:
        牛晓伟: @小宝拜财神 component不能有具体实现,具体实现是dagger2来生成的?不知答复你问题没
      • 我是午饭:写的很好,赞!
        牛晓伟: @我是午饭 谢谢
      • e959def2b035:前段时间学习RxJava看了你写的文章,现在学Dagger又看了你写的文章,真是太有缘分了,哈哈哈
        牛晓伟: @HarryCoder 😊
      • 小蜗牛snamon:好好干
      • 02744cada7f7:希望能结合具体的代码讲解一下效果会更好 看了也挺久的 上次只是找了例子能跑得起来 对于原理还是一点不懂 看这篇时翻出代码看了还是有点懞 若不嫌弃 可就我这里整理好的demo讲解一遍 期待ing...
        demo地址:http://pan.baidu.com/s/1nuYlAWh
        牛晓伟: @群里说 有时间的话可以
      • sgffsg:通俗易懂,循序渐进。。适合初学者,点赞
      • fe9fe0de7b28:非常清楚明白,非常好
      • 张庚:楼主,你之前看的那些开源项目用了dagger2给贴出来吧,多谢! :smile:
      • 艾幻翔:看完后还是云里雾里,Component到底怎么用呀?
      • 15c718193b10:您好?请问您有写好的比较简单的Demo吗?虽然概念上清楚了很多,但是开始写还是有点懵
        牛晓伟: @15c718193b10 最后一篇文章里有demo
      • 6aab7d3b21ce:看了这么多文章,终于看懂了一个。

      本文标题:Android:dagger2让你爱不释手-基础依赖注入框架篇

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