Dagger2神器入门(三)

作者: 黑马有点白986 | 来源:发表于2017-07-07 13:07 被阅读1659次

    前言

    Dagger2神器入门(二)中,我们通过简单的demo初步入门了Dagger2的简单使用,我们了解了@Inject,@Module,@Provides和@Componet等注解的使用方法。在这一章节中我们主要解决上篇文章中留下的3个问题:

    1 为什么要使用Dagger2来替代文章一开头的写法?
    2 如果@Inject的构造器有多个怎么办?
    3 如何存在依赖链怎么办?
    

    1 为什么要使用Dagger2来替代文章一开头的写法?

    我们先回回顾一下文章开头的写法:

    public class Car {
        private Engine engine;
        private Seat seat;
        private Wheel wheel;
        public Car() {
            engine = new Engine();
            seat = new Seat();
            wheel = new Wheel();
            Log.d(Config.TAG, "new Car()");
        }
      }
    

    再看看使用Dagger2之后的代码:

    public class Car {
    
      @Inject
      Engine engine;
      @Inject
      Seat seat;
      @Inject
      Wheel wheel;
      //  private Engine engine;
      //  private Seat seat;
      //  private Wheel wheel;
    
      public Car() {
      //  engine = new Engine();
      //  seat = new Seat();
      //  wheel = new Wheel();
        DaggerCarComponent
            .builder()
            .carModule(new CarModule())
            .build()
            .inject(this);
      Log.d(Config.TAG, "new Car()");
    
      }
    }
    

    那么问题来了?这样的写法好处在哪?
    1 如果我修改Engine类的构造器,那么对于第一种做法应该同时修改Car构造器的;如果还有N个地方依赖了我的Engine构造器怎么办?只能一个一个的去修改,这就增加了代码修改难度;而使用Dagger2呢?你的@Inject依赖还是不会变 ,只要修改一下Module类即可。
    2 再来看看第一种写法,虽然目的达到了,但是耦合度非常高;而第二种写法达到了解耦的目的。不能绝对的说哪种方式更好,这得看你的实际项目。

    2 @Inject注解的Class有多个构造器怎么办?

    神马意思呢?比如我们的车座可能会带一个座套,那么车座可能提供无车套车座和有车套车座。

    public class Seat {
        //默认无车套车座
        public Seat(){
            Log.d(Config.TAG,"new Seat()");
        }
        //提供有车套车座
        public Seat(String str){
            Log.d(Config.TAG,str);
        }
    }
    

    那么接着第二章代码,会输出啥呢?

      06-28 22:20:28.980 15053-15053/? D/TAG: new Engine()
      06-28 22:20:28.981 15053-15053/? D/TAG: new Seat()
      06-28 22:20:28.981 15053-15053/? D/TAG: new Wheel()
      06-28 22:20:28.981 15053-15053/? D/TAG: new Car()
    

    还是一样的输出?why?我们要想到我们提供依赖者?

        @Provides
        public Seat provideSeat(){
            return new Seat();
        }
    

    因为这里提供的构造器就是无参的,我们换一个有参数的试试?

         @Provides
          public Seat provideSeat(){
              return new Seat("有车套");
        }
    

    输出

      06-28 22:22:55.886 17342-17342/? D/TAG: new Engine()
      06-28 22:22:55.886 17342-17342/? D/TAG: 有车套
      06-28 22:22:55.886 17342-17342/? D/TAG: new Wheel()
      06-28 22:22:55.886 17342-17342/? D/TAG: new Car()
    

    那么有人会问,一个类能够提供2个provide呢?在Module中像这样写:

     @Provides
     public Seat provideSeat(){
          return new Seat();
      }
     @Provides
     public Seat provideSeat2(){
          return new Seat("有车套");
      }
    

    我们通过代码试试不就知道了?

    Error:(13, 11) 错误: com.bae.basicandext.dagger.blog.bean.Seat is bound multiple times:
    @Provides com.bae.basicandext.dagger.blog.bean.Seat com.bae.basicandext.dagger.blog.dagger.CarModule.provideSeat()
    @Provides com.bae.basicandext.dagger.blog.bean.Seat com.bae.basicandext.dagger.blog.dagger.CarModule.provideSeats()
    

    错误显示Seat类被绑定了多次。也就是说一个类只能提供一个构造器作为依赖。到这一步,我希望能够找到相关说明文档来再次验证自己的想法,因为我担心自己代码的错误导致自己错误的理解,官方文档给出的解释是100%正确的。

    @Inject官方解释

    @Inject can apply to at most one constructor per class。
    

    这就验证了我的做法是正确的,同时也验证我的猜想是正确的。

    3 如果存在依赖链怎么办?

    什么意思?这让我想起了设计模式中的责任链模式,在学习的过程中不断的联想,这是一种比较好的学习方法,因为我们要遵循艾宾浩斯遗忘曲线去学习,不但的巩固才能不断的提高自己。

    那么我们这里的依赖链是怎么回事呢?其实很简单,比如A依赖B,B依赖C,C依赖D...
    回归到我们的例子,我们的车座要依赖于皮革(leather),那么我们怎么办?

    public class Leather {
    public Leather(){
        Log.d(Config.TAG,"new Leather()");
      }
    }
    

    修改一下我们的车座,提供皮革依赖注入

    public class Seat {
        private Leather leather;
        public Seat(){
            Log.d(Config.TAG,"new Seat()");
        }
        public Seat(String str){
            Log.d(Config.TAG,str);
        }
        public Seat(Leather leather){
            this.leather = leather;
            Log.d(Config.TAG,"new Seat(Leather)");
        }
    }
    

    可以看到,我们在原有的基础之上增加了一个构造器Seat(leather), 而该构造器是存在依赖参数的。而我们需要在@Inject的时候就能自动调用该构造器,怎么办? 在之前讲到的提供依赖Module类修改

    @Provides
    public Seat provideSeat(Leather leather){
        return new Seat(leather);
    }
    

    仅仅这样是不行的,因为Module去寻找依赖Leather的时候会找不到对应对象,还需要添加

    @Provides
    public Leather provideLeather(){
        return new Leather();
    }
    

    这样在执行provideSeat() 时,能够找到相应的Leather();
    那么我们run下,先猜猜在

     @Inject
     Seat seat;
    

    这个中如何执行的?

    07-07 01:00:41.035 8144-8144/com.bae.basicandext D/TAG: new Engine()
    07-07 01:00:41.035 8144-8144/com.bae.basicandext D/TAG: new Leather()
    07-07 01:00:41.035 8144-8144/com.bae.basicandext D/TAG: new Seat(Leather)
    07-07 01:00:41.035 8144-8144/com.bae.basicandext D/TAG: new Wheel()
    07-07 01:00:41.035 8144-8144/com.bae.basicandext D/TAG: new Car()
    

    很明了了,它能够自动找到Leather依赖。其实关键的关键还是在Module类中。

    讲到这里,相信大家对Dagger2有一个初步认识,并且结合相关Api文档能够达到入门的目的了。接下来会一起学习一些其他Dagger2注解,期待吧...

    上一篇Dagger2神器入门(二)
    下一篇Dagger2神器入门(四)

    相关文章

      网友评论

      • 黑马有点白986:@千里之行死于足下 @Inject can apply to at most one construct per class。
        gstansen: @小腊月 但是我觉得你这样翻译容易导致歧义呢,或许这样翻译会更好些:一个类在某次提供依赖时只能提供一个构造方法或工厂方法。😂原谅我的扣细节
        黑马有点白986:@gstansen 但是你只是通过过滤器依赖了一个构造器而已
        gstansen:"也就是说一个类只能提供一个构造器作为依赖"
        这句话这样表述是有问题的,Dagger2还提供了@Named注解和@Qualifier注解用于区分同一个类的不同实例.
        在module里添加以上两个注解中的任意一个,并在使用@Inject注解时带上指定值的@Named注解或者自定义的@Qualifier注解就可以了.
      • 千里之行死于足下:第二个问题你只是把出现的问题说明了,可还是没说"怎么办"。如果我真的需要多个构造器并都要使用怎么办?
      • 冰的燃点:半夜醒来睡不着,看到妹子的文章甚是惊喜!文章写的很好通俗易懂,达到了深入浅出的境界👍妹子什么都好,就是数学不好,第三篇明明解决了三个问题开头却说解决2个问题,小小建议还望采纳😃
        黑马有点白986:@冰的燃点 哈哈,因为校对不仔细!感谢
      • 千里之行死于足下:这个 "Dagger2神器入门(二)"入口有问题啊
        黑马有点白986:感谢指出问题:http://www.jianshu.com/p/c673e6e73c8b

      本文标题:Dagger2神器入门(三)

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