Android依赖注入库Dagger的使用

关于依赖注入(Dependency Injection,简称DI)

类和类之间要建立联系,比如A类需要B类的实例对象,我们就说A类依赖B类,反过来,就说B类注入到A类中,所以“依赖注入”表示两层含义,依赖和注入。

View层面的DI

看了两个DI的库,AndroidAnnotation和Butter knife,个人感觉后者更好用一些,不会生成多余的类文件,都是view层面的DI,使用比较简单

自定义的DI

当然就是Dagger啦,跟Butter knife一样都是JakeWharton大神的作品。

Dagger使用java的注解,在预编译阶段就初始化了对象。Dagger的使用结构如下:
这里写图片描述
在下面的例子中,被注入者就是MainActivity,容器就是以“Module”结尾的类,而注入者就是实际的Teacher、Student类了。
先看被注入者Teacher:

public class Teacher {
    @Inject
    public Teacher(){

    }
    public void print(){
        System.out.println("hola: i am the teacher!");
    }
}

跟普通的类很像,只是多了一个@Inject注解,它表示这个类将来是要注入到其他类中去的,在构造函数使用。
下一个注入类,Student:

public class Student {
    String str;

    @Inject
    public Student() {

    }

    public Student(String name) {
        str = name;
    }

    public void print() {
        System.out.println("hola: string from Student default constructor");
    }

    public void printName() {
        System.out.println("hola: string from Student(String name) constructor: " + str);
    }

}

也是一样,不过有多个构造函数,怎么注入使用不同构造函数的对象待会再说。
注意,这里只能在一个构造函数中使用@Inject,否则报错:

Too many injectable constructors on com.ethan.daggertestsimple.Student

接着看第一个容器类TeacherModule:

@Module(library = true)
public class TeacherModule {
    @Provides Teacher provideTeacher(){
        return new Teacher();
    }
}

第二个容器类:

@Module(injects = MainActivity.class,library = true,includes = {TeacherModule.class})
public class StudentModule {
    @Provides
    public Student provideStudent(){
        return new Student();
    }
    @Provides @Named("Jake")
    public Student provideJakeStudent(){
        return new Student("Jake");
    }
    @Provides @Named("Ethan")
    public Student provideEthanStudent(){
        return new Student("Ethan");
    }
}

@Module就声明了这个类是个容器,这个接口中有很多方法,常见的(我用过的。。)有这几个:

//这个模块中的类被注入到哪里,这里是类数组,所以可以被注入到多个类中
Class<?>[] injects() default { };
//当前模块可以包含哪几个模块,也是类数组,模块之间可以嵌套,最终只能有一个模块,最终都要被嵌套到最高层的Module中去
Class<?>[] includes() default { };
//这个模块是不是完整的
boolean complete() default true;
//这个模块是不是作为库使用,如果不是,那么所有的方法必须得被调用,不然报错,所以声明为true为好
boolean library() default false;

@Provides是提供实例的方法注解,被它注解的方法回实例化被注入者(Student、Teacher)
@Named是javax.inject包中的接口,在这里可以用来区分调用哪个构造方法,如果这里@Provides只用一个方法,完全没有必要声明@Named

下面是被注入者MainActivity:

public class MainActivity extends AppCompatActivity {
    //在使用被注入对象时加入Inject,程序在DI过程中自动初始化
    @Inject
    Student stu;
    @Inject
    @Named("Jake")
    Student stuJake;
    @Inject
    @Named("Ethan")
    Student stuEthan;
    @Inject
    Teacher teacher;

    @Inject
    Provider<Student> stuList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ObjectGraph.create(StudentModule.class).inject(this);

        stu.print();
        stuJake.printName();
        stuEthan.printName();
        mutiStudent();
        teacher.print();
    }

    public void mutiStudent() {
        System.out.println("hola: =======student list========");
        for (int i = 0; i < 6; i++) {
            stuList.get().print();
        }
        System.out.println("hola: =======student list complete========");
    }
}

先不说别的,看着代码是不是很简洁,没有明确的实例化对象,但是在预编译阶段已经实例化了!

这里使用了Provider来提供对象数组,它同样来自javax.inject

下面看最关键的一行代码:

ObjectGraph.create(StudentModule.class).inject(this);

ObjectGraph是连接注入者与被注入者的类:

A graph of objects linked by their dependencies.

它的create方法会返回一个graph实例:

/**
   * Returns a new dependency graph using the {@literal @}{@link
   * Module}-annotated modules.
   *
   * <p>This <strong>does not</strong> inject any members. Most applications
   * should call {@link #injectStatics} to inject static members and {@link
   * #inject} or get {@link #get(Class)} to inject instance members when this
   * method has returned.
   *
   * <p>This <strong>does not</strong> validate the graph. Rely on build time
   * tools for graph validation, or call {@link #validate} to find problems in
   * the graph at runtime.
   */
  public static ObjectGraph create(Object... modules) {
    return DaggerObjectGraph.makeGraph(null, new FailoverLoader(), modules);
  }

然后通过inject方法将依赖注入到当前类中,被注入者和注入这就此连接起来了,后续就可以和平时一样使用已经初始化好的对象了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值