1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了。

2,接入项目

在项目的Gradle添加如下代码

dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
// 添加android-apt 插件
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}

  在app中的Gradle中添加导入

    // 应用插件
apply plugin: 'com.neenbedankt.android-apt' // dagger 2 的配置
compile 'com.google.dagger:dagger:2.4'
apt 'com.google.dagger:dagger-compiler:2.4'
compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解库

  简单的注解标签的介绍,由于之前写过一篇博客和大家思考过为什么使用Dagger2(它这么难使用为什么还要使用!!),并且还有一些常见注解标签的使用,所以这里就不和大家废话这么引入了,直接上干货

@Inject Inject主要有两个作用,一个是使用在构造函数上,通过标记构造函数让Dagger2来使用(Dagger2通过Inject标记可以在需要这个类实例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖,另一个作用就是标记在需要依赖的变量让Dagger2为其提供依赖。

@Provide 用Provide来标注一个方法,该方法可以在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Injection的变量赋值。provide主要用于标注Module里的方法

@Module 用Module标注的类是专门用来提供依赖的。有的人可能有些疑惑,看了上面的@Inject,需要在构造函数上标记才能提供依赖,那么如果我们需要提供的类构造函数无法修改怎么办,比如一些jar包里的类,我们无法修改源码。这时候就需要使用Module了。Module可以给不能修改源码的类提供依赖,当然,能用Inject标注的通过Module也可以提供依赖

@Component Component一般用来标注接口,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需要依赖方之间的桥梁,把相关依赖注入到其中。

@Singleton  该注解就是通过@scope定义的注解,一般用于提供全局单例。

   现在在实际场景中有这种情况,存在学生在老师的课堂上上课,那么一个学生可能存在多个老师,而一个老师也可能存在多个学生。这里我们为了方便解释,就直接转换成1对1的模式即一个学生只有一个老师,一个老师只有一个学生,然我们来看看转换成我们的java对象是什么样的,首先创建学生实体类

  Student.java

public class Student {
private int id;
private String name;
private Course[] course; public Student() {
System.out.println("Student create!!!");
} public Student(int id, String name, Course[] course) {
this.id = id;
this.name = name;
this.course = course;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Course[] getCourse() {
return course;
} public void setCourse(Course[] course) {
this.course = course;
} public void startLessons() {
System.out.println("开始上课了");
}
}

  我们的学生有一些基本的属性,如id、姓名、所学的课程,还有上课的动作。再看看我们创建老师类

public class Teacher {
Student student; public Teacher() {
student = new student();
} public void teacher() {
student.startLessons();
}
}

  这里我们就有一个问题了,我们老师类中需要一个学生的对象,而按照以前的方法我们肯定是在老师的构造方法中传递学生对象,毫无疑问肯定是new Student创建学生对象的,这里我们要使用Dagger2来代替(至于为什么要使用Dagger2代替,和代替之后有什么好处我以前写过,这里就不和大家废话了)

  首先在确定是我们Teacher类中的student属性需要Student对象,所以添加@Inject注解标签

    @Inject
Student student;

  而我们Dagger2要知道到底我是调用那个构造函数来创建Student对象啊,所以要在Student类中构造函数中添加@Inject标签,标明你Dagger2是要在这个构造方法里面创建的

public class Student {
private int id;
private String name;
private Course[] course; @Inject
public Student() {
System.out.println("Student create!!!");
} public Student(int id, String name, Course[] course) {
this.id = id;
this.name = name;
this.course = course;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Course[] getCourse() {
return course;
} public void setCourse(Course[] course) {
this.course = course;
} public void startLessons() {
System.out.println("开始上课了");
}
}

  然后我们 Student中对象被创建了,而我们Teacher中需要这个student对象,这时候我们差一个桥梁来链接这两个类,从而让我们被创建的student对象运送到需要它的地方,所以现在我们需要使用@Component标签,来修饰我们自定义的一个接口,创建TeacherComponent接口,并使用@Component注解标签修饰,创建inject方法(这里很多看过不少Dagger2文章的同学坑定会有疑问,这里的inject是固定方法名吗,能不能使用injectA啊之类的,先把问题留着,我们后面再讲)

package com.qianmo.rxjavatext;

import dagger.Component;

/**
* Created by Administrator on 2017/4/20 0020.
* E-Mail:543441727@qq.com
*/
@Component
public interface TeacherComponent {
void inject(Teacher teacher);
}

  再在我们Teacher类中初始化

 public Teacher() {
DaggerTeacherComponent.builder().build().inject(this);
}

  这时候可能有同学又有疑问了,DaggerTeacherComponent这个类怎么报错啊 ,其实这个类是编译时产生的类大家不用慌,把代码写完了crtl+F9编译一下就可以了,但是!!!这里DaggerTeacherComponent的书写方法是Dagger加上你前面自定义的Component接口类的类名,一定要注意,不然很多同学都会在这翻车(我曾经在这儿翻出无数次),然后再说一下我们上一个问题 TeacherComponent 中的inject方法是固定方法吗?很明显这里调用的是inject(this);所以不是固定方法,只不过你Component接口类写成injectA(Teacher teacher),那么你这里调用的方法就是injectA(this)

  ok,上面这些都写好了,我们在Teacher类中添加测试类来测试测试

public class Teacher {
//想持有学生对象
@Inject
Student student; public Teacher() {
DaggerTeacherComponent.builder().build().injectA(this);
} public void teacher() {
student.startLessons();
} public static void main(String[] args) {
new Teacher().teacher();
}
}

  看一下打印效果

Student create!!!
开始上课了

3,源码分析

  ok,没什么问题,那我们现在只是停留在会用的阶段,底层我们的源码到底是怎么吧我们的对象创建出来的,还有怎么将我们的对象设置到需要它的地方呢,不要慌,老司机现在就带你来看看源码是什么实现的。这里的源码很简单,一共涉及到三个类,都是我们运行时生成的DaggerTeacherComponent、Teacher_MembersInjector、Student_Factory。

  先来看看DaggerTeacherComponent,按照字面意思这是我们Teacher的桥梁类,源码如下:

package com.qianmo.rxjavatext;

import dagger.MembersInjector;
import javax.annotation.Generated; @Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerTeacherComponent implements TeacherComponent {
private MembersInjector<Teacher> teacherMembersInjector; private DaggerTeacherComponent(Builder builder) {
assert builder != null;
initialize(builder);
} public static Builder builder() {
return new Builder();
} public static TeacherComponent create() {
return builder().build();
} @SuppressWarnings("unchecked")
private void initialize(final Builder builder) { this.teacherMembersInjector = Teacher_MembersInjector.create(Student_Factory.create());
} @Override
public void injectA(Teacher teacher) {
teacherMembersInjector.injectMembers(teacher);
} public static final class Builder {
private Builder() {} public TeacherComponent build() {
return new DaggerTeacherComponent(this);
}
}
}

  我们首先来看我们之前的调用方法如下

DaggerTeacherComponent.builder().build().injectA(this);

  首先看一下DaggerTeacherComponent.builder()方法,我们从源码中可以看到DaggerTeacherComponent.builder()调用生成了一个Builder 对象,我们继续代用builder.builder()方法,而我们的build类中代码如下(这里再次吐槽博客园的编辑器,在线编辑的时候无法显示引用代码的行号,这样我们就没法通过行号来解释每一行代码的意思,而必须要重写贴一次代码,操蛋!!!):

 public static final class Builder {
private Builder() {} public TeacherComponent build() {
return new DaggerTeacherComponent(this);
}
}

  “new DaggerTeacherComponent(this);” 看到没,实际上是调用我们的DaggerTeacherComponent对象,而我们的DaggerTeacherComponent构造函数是调用的initialize()方法,看一下方法里面具体代码

@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.teacherMembersInjector = Teacher_MembersInjector.create(Student_Factory.create());
}

  这时候出现了Teacher_MembersInjector、Student_Factory类,我们先不要管,继续往下看,上面我们调用完builder.builder()方法方法之后,再调用injectA(this)的方法,具体代码如下:

@Override
public void injectA(Teacher teacher) {
teacherMembersInjector.injectMembers(teacher);
}

  呃,这里我们又看到Teacher_MembersInjector这个类对象了,所以这时候看看我们Teacher_MembersInjector的源码了,我们上面一共在两个地方使用了Teacher_MembersInjector,一个是.create方法,一个是injectMember方法,所以我们主要要留心源码里面这两个类,具体源码如下:

package com.qianmo.rxjavatext;

import dagger.MembersInjector;
import javax.annotation.Generated;
import javax.inject.Provider; @Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class Teacher_MembersInjector implements MembersInjector<Teacher> {
private final Provider<Student> studentProvider; public Teacher_MembersInjector(Provider<Student> studentProvider) {
assert studentProvider != null;
this.studentProvider = studentProvider;
} public static MembersInjector<Teacher> create(Provider<Student> studentProvider) {
return new Teacher_MembersInjector(studentProvider);
} @Override
public void injectMembers(Teacher instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.student = studentProvider.get();
} public static void injectStudent(Teacher instance, Provider<Student> studentProvider) {
instance.student = studentProvider.get();
}
}

  先看看.create方法,可以看到就是很简单的new Teacher_MembersInjector ,相当于初始化了一些成员变量studentProvider ,至于studentProvider 是什么,从字面的意思上来看是我们student的提供者,那么是时候我们就再来看看Student_Factory.create()方法了,因为是这个类提供了studentProvider 对象

package com.qianmo.rxjavatext;

import dagger.internal.Factory;
import javax.annotation.Generated; @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;
}
}

  窝草,请看get方法中的 “new Student()”代码,这不就是我们的student对象的创建嘛,原来你在这里,再看一下在哪里调用我们的studentProvider.get方法拿到创建的Student对象,这时候请看Teacher_MembersInjector.injectMembers()方法,具体代码如下:

@Override
public void injectMembers(Teacher instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.student = studentProvider.get();
}

  看到我们倒数第二行了没,在这里我们拿到teacher对象,设置它的成员变量student。ok,到这里我们就懂了,整个逻辑就全部通了,首先DaggerTeacherComponent.builder().build()执行完在Student_Factory中创建好了student对象,然后在调用injectA(this)方法,将创建的student对象放置到teacher对象中的student属性上。

  OK,到这里我们就简单的了解了Dagger2的使用了,写到这里篇幅已经比较长了,所以我打算用三篇文章来和大家吃透Dagger2,和大家一起从源码入坑到跳坑,最后,还有一个很关键事忘说了:最近打算辞职回北京,有没有大神同学推荐工作,带带小弟啊.

  下一篇:Android -- 带你从源码角度领悟Dagger2入门到放弃(二)

Android -- 带你从源码角度领悟Dagger2入门到放弃(一)的更多相关文章

  1. Android -- 带你从源码角度领悟Dagger2入门到放弃

    1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...

  2. Android -- 带你从源码角度领悟Dagger2入门到放弃(二)

    1,接着我们上一篇继续介绍,在上一篇我们介绍了简单的@Inject和@Component的结合使用,现在我们继续以老师和学生的例子,我们知道学生上课的时候都会有书籍来辅助听课,先来看看我们之前的Stu ...

  3. Android -- 带你从源码角度领悟Dagger2入门到放弃(三)

    1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用 在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的Green ...

  4. 消息队列高手课,带你从源码角度全面解析MQ的设计与实现

    消息队列中间件的使用并不复杂,但如果你对消息队列不熟悉,很难构建出健壮.稳定并且高性能的企业级系统,你会面临很多实际问题: 如何选择最适合系统的消息队列产品? 如何保证消息不重复.不丢失? 如果你掌握 ...

  5. Android 带你从源码的角度解析Scroller的滚动实现原理

    转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢! 今天给大 ...

  6. Android AsyncTask完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...

  7. [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...

  8. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  9. [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解

    我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...

随机推荐

  1. Linux下printf、fprintf、sprintf的区别

    (1)fprintf() int fprintf( FILE *stream, const char *format, ... );   用于文件操作,根据指定的format(格式)发送信息(参数)到 ...

  2. Android Bluetooth hci 命令分析

    Android在连接BLE设备的时候,遇到连接没多久就自动断开的情况.通过HCI来分析一下. BLE设备发送连接参数更新请求 3909 15:53:01.224737 TexasIns_f0:d3:4 ...

  3. Angularjs 学习笔记

    Angularjs 表单验证:https://www.w3xue.com/jsjq/angularjs/angularjs-validation.html https://www.cnblogs.co ...

  4. 如何查看已经安装的nginx、apache、mysql和php的编译参数

    1.nginx编译参数: nginx -V(大写) #注意:需保证nginx在环境变量中,或者使用这样的形式:/user/local/nginx/sbin/nginx -V 2.apache编译参数 ...

  5. 如何免费下载付费音乐歌曲,6个网站+8个APP

    现在听音乐的软件,QQ音乐,酷狗,网易云等,很多歌曲可以在线听. 但是下载某些歌曲或者在线听高品质无损的都需要付费. 这一期,给大家推荐的是免费下载付费歌曲工具,包括网站跟APP. 网站篇 1.VIP ...

  6. thinphp5框架遇到 mkdir() Permission denied 解决办法

    网站重装 直接复制本地程序文件 里面数据库链接信息要改成线上的 然后mysql apache 等都没有动 运行后出现错误 mkdir() Permission denied 这是由于runtime目录 ...

  7. Centos 为Nginx 搭建https

    Youtube Nginx 扩展模块 certbot文档 yum -y install epel-release yum -y install certbot certbot certonly --s ...

  8. Linux 的基本操作(文件与目录管理)

    文件与目录管理 在linux中什么是一个文件的路径呢,说白了就是这个文件存在的地方,例如在上一章提到的/root/.ssh/authorized_keys 这就是一个文件的路径.如果你告诉系统这个文件 ...

  9. css 背景图片虚化效果

    转载地址:http://blog.csdn.net/ohehehou/article/details/51975539 需求:一个div设置了background: url,现在需要使图片背景模糊,d ...

  10. jqeury点击空白关闭弹窗

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...