Android Dagger2依赖注入库使用详解

导语


    依赖注入是一种面向对象的编程模式,它的出现是为了降低耦合性。可能有的人觉得之前并没有使用过依赖注入,其实当我们在类的构造函数中通过参数引入对象或通过set方法设置类的对象时,就是依赖注入。而通过注解的方式完成的依赖注入就是本篇要讲的Dagger库的使用。


添加依赖build.gradle

  compile 'com.google.dagger:dagger:2.7'
  annotationProcessor 'com.google.dagger:dagger-compiler:2.7'


*如果,build项目抛出“ Execution failed for task ':app:javaPreCompileDebug” 就在gradle中填写下面代码。

 
defaultConfig {
    javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
}


如何使用

1、 创建Student类:

public class Student {

    @Inject
    public Student() {
    }
}

Student类中有一个空的构造方法,并且在构造方法上面添加了一个@Inject注解。

然后,我们使用ctrl+F9(mac使用Cmd+F9)进行一次编译,查看项目路径:

app\build\generated\source\apt\debug\com\mei_husky\sample_dagger2\model\Student_Factory.java

会发现编译器自动生成了一个Student_Factory类:

@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public enum Student_Factory implements Factory<Student> {
  INSTANCE;

  @Override
  public Student get() {
    return new Student();
  }

  public static Factory<Student> create() {
    return INSTANCE;
  }
}

一个工厂类,在通过create()创建后,每次调用get()方法都能获得一个Student对象。

小结:通过@Inject注解了一个类的构造方法后,可以让编译器帮助我们产生一个对应的Factory类,通过这个工厂类我们可以通过简单的get()方法获取到Student对象。


2、调用Student类:

public class A01SimpleActivity extends AppCompatActivity {

    @BindView(R.id.btn_01)
    Button btn01;

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a01_simple);
        ButterKnife.bind(this);
    }

    @OnClick(R.id.btn_01)
    public void onViewClicked(View view) {
        switch (view.getId()){
            case R.id.btn_01:             
                Toast.makeText(this,student.toString(),Toast.LENGTH_SHORT).show();
            break;
        }
    }
}

Activity类中创建一个成员变量Student,按照Dagger2给我们的指示,当我们需要一个Student,我们只需要在这个成员变量上方加一个@Inject注解,编译器会自动帮我们产生对应的代码,我们就可以直接使用这个Student对象了!运行代码,并点击Button直接报空指针异常:

这里写图片描述

小结:@Inject并没有帮助我们初始化对应的Student对象,或者说,我们的Activity并没有使用刚才我们看到的Student_Factory类。这是因为缺少建立Activity和Student_Factory类之间的关系。


3、Module和Component使用

接下来创建Module类、Component接口:

@Module
public class A01SimpleModule {

    private A01SimpleActivity activity;

    public A01SimpleModule(A01SimpleActivity activity) {
        this.activity = activity;
    }
}
@Component(modules = A01SimpleModule.class)
public interface A01SimpleComponent {

    void inject(A01SimpleActivity activity);

}
  • Module类上方的@Module注解意味着这是一个提供数据的"模块";
  • @Component(modules = A01SimpleModule.class)注解意味着这是一个"组件" 或称作:注射器。

继续在之前Activty中添加下面一段代码,运行后调用成功。

public class A01SimpleActivity extends AppCompatActivity {
    @BindView(R.id.btn_01)
    Button btn01;

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a01_simple);
        ButterKnife.bind(this);
        //新添代码
        DaggerA01SimpleComponent.builder()
                .a01SimpleModule(new A01SimpleModule(this))
                .build()
                .inject(this);
    }

    @OnClick(R.id.btn_01)
    public void onViewClicked(View view) {
        switch (view.getId()){
            case R.id.btn_01:
                Toast.makeText(this,student.toString(),Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

小结:添加了Module和Component类,然后在Activity中添加一段代码,被@Inject的Student类被成功依赖注入到了Activity中,并且其他地方也可以使用上面一段代码调用Student类,这样就降低了Student的耦合度。


为什么要使用依赖注入?

    这时候不可避免的,有些同学会有些疑问,我们需要一个Student对象,完全可以直接通过new的方式创建一个嘛?这是因为通常简单的代码具有耦合性,而要想降低这样的耦合就需要其他的辅助代码,其实代码量和耦合度这是两码事。试想,我们如果通过这样的方式,在其他的文件中创建1000个文件使用Student对象,那么至少要new 1000个新的Student类对象。这时,新的需求到了,Student类需要改动内部属性和字段, 可能需要分别对这1000个文件中逐个修改调用的代码。如果使用Dagger2,我们只需要在Student类中做出简单的修改即可轻松完成对Student的构造修改问题,达到低耦合的效果即可。


Component、Module如何理解?

假设,案例中的Activity——代表学校,Student——代表某学生。现在学校(Activity)要开学了,需要学生(Student)去报名。OK,接下来,学生肯定要在家整理行李(家代表着自动生成的Student_Factory)。虽然这位学生(Student)已经从家(Student_Factory)准备出发了,但是距离学校(Activity)还是有一段距离的,肯定需要一种交通方式(Component)。

   交通方式(Component)就是一种注入器,将学生(Student)送到学校(Activity)。即如下代码:

  DaggerA01SimpleComponent.builder()
          .a01SimpleModule(new A01SimpleModule(this))
          .build()
          .inject(this);

这时可能会问,Module到底干什么的呢?

首先,我们可以注释调Module的代码,结果,发现我们依然可以正常使用Student对象。

        DaggerA01SimpleComponent.builder()
              //.a01SimpleModule(new A01SimpleModule(this))//注释掉这行代码
                .build()
                .inject(this);

我们可以暂时可以这样理解Module,它的作用就是交通方式的一种叫“公交车”。学生乘坐公交车就可以去学校,比较好理解。

然后,重写Student类,取消了@Inject注解。

public class Student {
    //取消注解
    public Student() {
    }
}
Module类添加代码:
@Module
public class A01SimpleModule {

    private A01SimpleActivity activity;

    public A01SimpleModule(A01SimpleActivity activity) {
        this.activity = activity;
    }
    //下面为新增代码:
    @Provides
    Student provideStudent(){
        return new Student();
    }
}

最后,Component类代码不变,在Activity中调用Student对象,结果依然正常。

 DaggerA01SimpleComponent.builder()
                .a01SimpleModule(new A01SimpleModule(this))
                .build()
                .inject(this);

小结:原因是,虽然@Inject注解取消了,但是,已经在公交车(Module)上强行提供 @Providers 一个学生进行乘坐,然后学生被这种交通方式(Component)送到学校(Activity)。


总结


经过简单的使用Dagger2,我们已经可以基本有了以下了解:

  • @Inject : 注入,被注解的构造方法会自动编译生成一个Factory工厂类提供该类对象。
  • @Component: 注入器,类似快递员,作用是将产生的对象注入到需要对象的容器中,供容器使用。
  • @Module: 模块,类似快递箱子,在Component接口中通过@Component(modules = xxxx.class),将容器需要的商品封装起来,统一交给快递员(Component),让快递员统一送到目标容器中。

————————————————————————————

本文参考:Android 神兵利器Dagger2使用详解(一)基础使用

源码请看: Android 神兵利器Dagger2使用详解(二)Module&Component源码分析


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾阳Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值