安卓开发 第一篇 关于依赖注入框架dagger2的使用和理解

(这篇博客真是磨难重重啊,写到一半电脑蓝屏了,还好markdown编辑器保持了部分类容)

最近开始重构项目,在重构项目中用到了依赖注入框架dagger2,发现它确实很方便,能大大加快我们编写代码的速度,同时也很方便我们对于功能模块的解耦。在这里就不过多介绍dagger2了,大家谷歌 百度一下就能得到很多关于dagger2的介绍。学习dagger2是需要一定的学习成本的,我自己开始学习的时候也差不多花了一周的时间才弄明白怎样使用dagger2,下面就说说自己对dagger2的理解和使用方法。

  1. dagger2中最重要的就是module和component了,module是生产我们需要的对象的地方,component是联系module和module生产出的对象的使用场景的桥梁。(说白了,dagger2就像是设计模式中的工厂模式,为我们生产各种我们需要的对象)

    不明白?上代码:(假如我们有一个类A,然后我们通过依赖注入方法要在MainActivity中使用)

    • 不使用dagger2

      类A:

      public class A {
          private  int field;
            ...       //其他属性
      
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      类MainActivity

      public class MainActivity extends AppCompatActivity {
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              A a=new A();
              a.doSomething();
              a.doOtherthing();
          }
      }
    • 使用dagger2

      类A:

       public class A {
          private  int field;
            ...       //其他属性
      
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      我们先要构造一个Module,这个Module中生产A的对象

      @Module
      public class AMedule {
      
          @Provides
          A  provideA(){
              return  new A();
          }
      
      }

      然后需要一个Component,用了连接Module和MainActivity

      @Component(modules = AMedule.class)
      public interface ActivityComponent {
         A a();
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              ActivityComponent component=DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build();
      
              A a=component.a();
              a.doSomething();
              a.doOtherthing();
          }
      }

      一个简单的依赖注入就完成了。

      也许大家会觉得这样写很麻烦,其实不然,还有一种更加简单的方法来做这件事,我们把MainActivity注入到ActivityComponent中,直接使用@Inject注解:

    • 使用@Inject注解

      类A :

       public class A {
          private  int field;
            ...       //其他属性
      
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      我们先要构造一个Module

      @Module
      public class AMedule {
      
          @Provides
          A  provideA(){
              return  new A();
          }
      
      }

      然后需要一个Component

      @Component(modules = AMedule.class)
      public interface ActivityComponent {
          void inject(MainActivity mainActivity);
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build()
                      .inject(this);
      
      
              a.doSomething();
              a.doOtherthing();
          }
      }
      

      怎么样,是不是简单,方便一些了。

      什么?还麻烦,那我们更进一步吧(由于这里的A类是我们自己定义的,可以更进一步):

    • 更进一步的@Inject注解

      类A :

       public class A {
          private  int field;
            ...       //其他属性
      
          @Inject
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      我们先要构造一个Module(其实这里Module已经用不到了,我们不需要通过Modu生产A了,不过为了与上面对比,还是留着吧)

      @Module
      public class AMedule {
      
      //    @Provides
      //    A  provideA(){
      //        return  new A();
      //    }
      
      }

      然后需要一个Component

      @Component(modules = AMedule.class)
      public interface ActivityComponent {
          void inject(MainActivity mainActivity);
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build()
                      .inject(this);
      
              a.doSomething();
              a.doOtherthing();
          }
      }

      是不是看迷糊了,A没有在Module生产,那是怎么来的呢?不知道大家注意到没有,A的构造方法上面有个@Inject注解,没错,就是他,就是这个注解生产A对象的。

      看到这里,我们就知道dagger2生产对象有两种方式,一种是在Module中通过@Provides注解加上providexxx 方法,另一种就是直接在要生产的对象的类的构造方法加上@inject注解。

      那么什么时候用Module,什么时候用@Inject呢?

      在这里悄悄告诉大家: 一般生成系统或者SDK或者第三方库提供的类的对象时用Module,而自定义的类的对象用@Inject,当然,你也可以用一个类继承系统或者SDK或者第三方库提供的类,然后在其构造方法加上@Inject注解。

    2.可能大家对Module和Component的还是似懂非懂,在这里在打一个形象一点的比喻吧。

    例如到吃饭的时间了,我们要去做饭(吃外卖的绕道),我们得去厨房吧(希望不是野外烧烤),我们需要煤气灶(也可能是电磁炉),锅,刀,砧板,盆子….(发现需要的真多哈),这些都是一个个类吧,你厨房里的那些具体的比如美的电饭煲(美的是不是得给点广告费),苏泊尔不粘锅(刚买了一个)…..就是一个个具体的对象,我们有了这些具体的对象才能愉快的做饭,而Module就是让我们得到这一个个对象(一个大工厂,生产美的电饭煲,苏泊尔不粘锅….),Component 就是我们的厨房,DaggerActivityComponent .builder().aMedule(new AMedule()).build() 就是让我们拥有了一个厨房(想想机器猫的口袋,我们可以从里面得到任何东西 ),我们可以从厨房里面拿炊具做饭(往外拿:A a=component.a(),这是把厨房里的东西拿到厨房外面,在外面做饭),而 DaggerActivityComponent.builder() .aMedule(new AMedule()) .build().inject(this)就是我们自己进入厨房,在厨房里面 做饭(我们当然很容易获得厨房里面的炊具了,用@Inject获得),好了,开始做饭…

    3.一个Component可以依赖多个Module,如

     @Component(modules = {AModule.class,BModule.class,...})

    同样,Component也可以依赖另一个Component,如

    @Component(dependencies = BComponent.class,modules = {AModule.class,BModule.class,...})

    甚至多个Component,如

    @Component(dependencies = {BComponent.class,CComponent.class,...}
                 ,modules = {AModule.class,BModule.class,...})

    有个需要注意的地方是被依赖的Component需要将对象暴露出来,依赖的Component才能够获取到这个对象,如

    被依赖Component

        @Component(modules = {...})
        public interface BComponent {
            A a();
            B b();
        }

    依赖Component

        @Component(dependencies = BComponent.class,modules = {...})
            public interface CComponent {
    
            }
    

    CComponent可以通过BComponent获取A,B的对象,其他BComponent的对象对CComponent来说是透明的,不可见。

    4.@Scope注解

    这个注解是用来划分作用域的(在哪儿使用),意思就是说我划出一块区域来,生产出的东西如果限定到此作用域都放到这里,作用域的场景类(一般就是消费对象的地方,比如Activity)下次需要某个对象的时候,我就来这儿拿,如果有,就直接拿来用,如果没有,就生产,并且放到这里,同时自己用(有没有一种方便自己,方便他人的感觉),dagger2自已有个@Scope注解,叫@Singleton,就是大家都熟悉的单例模式,你也可以自定义@Scope注解,比如限定生产出的某个对象只能在Activity中使用,只能在Application中使用,只能在Fragment中使用等等。。。

    例如:我们写一个限定作用域为Activity的Scope注解

    @Scope
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PerActivity {
    
    }
    
    
    • 使用(构造函数方式)

      类A :

      @PerActivity
       public class A {
          private  int field;
            ...       //其他属性
      
          @Inject
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      然后需要一个Component

      @PerActivity
      @Component()
      public interface ActivityComponent {
          void inject(MainActivity mainActivity);
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .build()
                      .inject(this);
      
              a.doSomething();
              a.doOtherthing();
          }
      }
    • 使用(Module方式)

      类A :

       public class A {
          private  int field;
            ...       //其他属性
      
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      我们先要构造一个Module

      @Module
      public class AMedule {
      
         @PerActivity
         @Provides
          A  provideA(){
              return  new A();
          }
      
      }

      然后需要一个Component

      @PerActivity
      @Component(modules = AMedule.class)
      public interface ActivityComponent {
          void inject(MainActivity mainActivity);
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build()
                      .inject(this);
      
              a.doSomething();
              a.doOtherthing();
          }
      }

      没看明白?好吧,我们继续

      假如我们还有一个SecondActivity也要使用A的对象

      类A :

       public class A {
          private  int field;
            ...       //其他属性
      
          public A() {
          }
      
          public void doSomething(){
              Log.i("美女","我爱你");
          }
      
          public void doOtherthing(){
              Log.i("美女","我是真的爱你");
          }
          ...    //其他方法
      }

      我们先要构造一个Module

      @Module
      public class AMedule {
      
         @PerActivity
         @Provides
          A  provideA(){
              return  new A();
          }
      
      }

      然后需要一个Component

      @PerActivity
      @Component(modules = AMedule.class)
      public interface ActivityComponent {
          void inject(MainActivity mainActivity);
          void inject(SecondActivity secondActivity);
      }

      在MainActivity类中使用

      public class MainActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build()
                      .inject(this);
      
              a.doSomething();
              a.doOtherthing();
          }
      }

      在SecondActivity类中使用

      public class SecondActivity extends AppCompatActivity {
          @Inject
          A a;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
             DaggerActivityComponent.builder()
                      .aMedule(new AMedule())
                      .build()
                      .inject(this);
      
              a.doSomething();
              a.doOtherthing();
          }
      }

      那么,这里MainActivity和SecondActivity中的A的对象a是同一个

    5.子Component

    子Component跟前面的一个Component依赖另一个Component有点像,区别是子Component可以获取到父Component的所有可以生产出的对象,而Component依赖则只能获取到被依赖的Component所暴露出来的可以生产的对象。 例子:

    类A :

            public class A {
               private  int field;
                  ...       //其他属性
    
                public A() {
                }
    
                public void doSomething(){
                    Log.i("美女","我爱你");
                }
    
                public void doOtherthing(){
                    Log.i("美女","我是真的爱你");
                }
                ...    //其他方法
            }

    我们先要构造一个Module

            @Module
            public class AMedule {
    
               @Provides
                A  provideA(){
                    return  new A();
                }
    
            }

    然后需要一个Component

            @Component(modules = AMedule.class)
            public interface ActivityComponent {
                void inject(MainActivity mainActivity);
    
                CComponent plus(Module1 module1,Module2 module2,...);//参数为CComponent依赖的Module
    
            }

    然后一个子Component(使用@Subcomponent注解)

            @Subcomponent(modules = {...})
            public interface CComponent {
    
                void inject(SecondActivity secondActivity);
            }

    在MainActivity类中使用,将MainActivity注入到父Component中

        public class MainActivity extends AppCompatActivity {
            @Inject
            A a;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
               DaggerActivityComponent.builder()
                        .aMedule(new AMedule())
                        .build()
                        .inject(this);
    
                a.doSomething();
                a.doOtherthing();
            }
        }

    在SecondActivity类中使用,将SecondActivity注入到子Component中

        public class SecondActivity extends AppCompatActivity {
            @Inject
            A a;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
               DaggerActivityComponent.builder()
                        .aMedule(new AMedule())
                        .build()
                        .plus(new Module1(),new Module2(),...)//CComponent依赖的Module
                        .inject(this);
    
                a.doSomething();
                a.doOtherthing();
            }
        }
    

    6.@Named注解

    这个注解是用来设置别名的,用来区分同一个类型的不同对象。比如我们都知道Android 中的Context有两种,一种是全局的,一种是Activity中的,为了区分他们,我们就可以加上别名;又比如有一个Person类,他有两个实例,一个是小李,一个是小美,我们也可以用别名区分他们。

    Person类 :

        public class Person {
            private String name;
            private int age;
    
            public Person() {
            }
    
            public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
    
           @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }

    我们先要构造一个Module

        @Module
        public class ActivityMedule {
           @Named"小李"@Provides
            Person  providePerson(){
                return  new Person("小李"18);
            }
           @Named"小美"@Provides
            Person  providePerson(){
                return  new Person("小美"24);
            }
    
        }

    然后需要一个Component

        @Component(modules = ActivityMedule.class)
        public interface ActivityComponent {
            void inject(MainActivity mainActivity);
        }

    在MainActivity类中使用

        public class MainActivity extends AppCompatActivity {
            @Named"小李"@Inject
            Person p1;
    
            @Named"小美"@Inject
            Person p2;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
               DaggerActivityComponent.builder()
                        .activityMedule(new ActivityMedule())
                        .build()
                        .inject(this);
    
                Log.i("person",p1.toString());
                Log.i("person",p2.toString());
            }
        }

    当然,如果你觉得@Named注解满足不了你的需求,你也可以使用@Qualifier来自定义自己的别名注解

    7.构造函数注入和方法注入(补充)

    之前写文章的时候忘了这个内容了,有点不好意思,看到这篇文章这么受大家的欢迎,心中很高兴,决定尽量做到完美。

    构造函数注入和方法注入其实差不多,都是为我们要生产的对象提供他要依赖的其他对象,不明白?看代码吧

    BeautyGirl类:

        public class BeautyGirl{
            private String name;
    
            private int age;  //恕罪 恕罪,女人的年龄是禁忌
    
            ...  //其他属性
    
            public void setName(String name){
            this.name = name;
            }
            public String getName(){
            return this.name;
            }
            public void setAge(int age){
            this.age = age;
            }
            public int getAge(){
            return this.age;
            }
    
            ...    //其他方法
        }

    类A :

        public class A {
            private  int field;
    
            private BeautyGirl girl;
    
              ...       //其他属性
    
            @Inject
            public A(BeautyGirl girl) {
                 this.girl=girl;
            }
    
            public void doSomething(){
                Log.i("美女",girl.getName+"我爱你");
            }
    
            public void doOtherthing(){
                Log.i("美女",girl.getName+"我是真的爱你");
            }
            ...    //其他方法
        }

    我们先要构造一个Module,生产BeautyGirl

        @Module
        public class AMedule {
    
           @PerActivity
           @Provides
            BeautyGirl  provideBeautyGirl(){
               BeautyGirl gril= new BeautyGirl();
               girl.setName("天上少有,地上没有的大美女");
               girl.setAge(20);
    
               return girl;
            }
    
        }

    然后需要一个Component

        @PerActivity
        @Component(modules = AMedule.class)
        public interface ActivityComponent {
            void inject(MainActivity mainActivity);
        }

    在MainActivity类中使用

        public class MainActivity extends AppCompatActivity {
            @Inject
            A a;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
               DaggerActivityComponent.builder()
                        .aMedule(new AMedule())
                        .build()
                        .inject(this);
    
                a.doSomething();
                a.doOtherthing();
            }
        }

    明白了没,A的依赖对象BeautyGirl是通过构造参数从外部传入的(也就是一个依赖注入),当构造方法或者其他方法添加了@Inject注解的时候,我们要生产这个类的对象的时候首先就会去查找满足的依赖,然后才会生产我们需要的对象。(方法注入就不讲了,跟构造函数一样,只不过构造函数添加@Inject注解,在场景类(上面的MainActivity)就可以直接通过@Inject生产这个对象)

    8.在android studio的使用,在build.gradle中添加依赖库

    compile 'com.google.dagger:dagger:2.2' 
    compile 'com.google.dagger:dagger-compiler:2.2' 
    provided 'org.glassfish:javax.annotation:10.0-b28'

    好了,大概就讲这么多吧!

    如果有更深的理解,本文将会修改;
    如果有错误的地方,欢迎指正;
    如果你有更好的理解,欢迎交流。

    本文为原创文章,版权归博主所有,转载请注明出处。

    更多资料:
    dagger官方github地址 : https://github.com/google/dagger
    dagger2在android中使用 :http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/
    我的github地址以及使用demo: https://github.com/naivor/naivorapp

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值