Android依赖注入库Dagger的使用

来源:互联网 发布:生物信息学 知乎 编辑:程序博客网 时间:2024/05/16 15:22

关于依赖注入(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方法将依赖注入到当前类中,被注入者和注入这就此连接起来了,后续就可以和平时一样使用已经初始化好的对象了!

0 0
原创粉丝点击