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注解标签

    @InjectStudent student;

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

public class Student {private int id;private String name;private Course[] course;@Injectpublic 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 {//想持有学生对象@InjectStudent 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());}@Overridepublic 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)的方法,具体代码如下:

@Overridepublic 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);}@Overridepublic 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;@Overridepublic Student get() {return new Student();}public static Factory<Student> create() {return INSTANCE;}
}

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

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

  2. 带你从源码角度分析ViewGroup中事件分发流程

    序言 这篇博文不是对事件分发机制全面的介绍,只是从源码的角度分析ACTION_DOWN.ACTION_MOVE.ACTION_UP事件在ViewGroup中的分发逻辑,了解各个事件在ViewGroup ...

  3. Redis源码阅读,从入门到放弃

    作为后端工程师,我们在面试和工作中都会用到 Redis,特别是大型互联网公司面试时,不仅要求面试者能简单使用 Redis,还要求懂 Redis 源码层面的实现原理,具备解决常见问题的能力.可以说,熟练 ...

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

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

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

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

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

    <div id="container">         <div id="header">     <div class=&qu ...

  7. 从源码角度解析Android中APK安装过程

    从源码角度解析Android中APK的安装过程 1. Android中APK简介 Android应用Apk的安装有如下四种方式: 1.1 系统应用安装 没有安装界面,在开机时自动完成 1.2 网络下载 ...

  8. 【Android 插件化】Hook 插件化框架 ( 从源码角度分析加载资源流程 | Hook 点选择 | 资源冲突解决方案 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  9. 从源码角度看Android系统Launcher在开机时的启动过程

    Launcher是Android所有应用的入口,用来显示系统中已经安装的应用程序图标. Launcher本身也是一个App,一个提供桌面显示的App,但它与普通App有如下不同: Launcher是所 ...

最新文章

  1. 一个purge参数引发的惨案——从线上hbase数据被删事故说起
  2. ViewPager 的适配器 PagerAdapter 、FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别
  3. Docker安装mysql8
  4. P6623-[省选联考2020A卷]树【Trie,树上启发式合并】
  5. JavaScript 所有数据类型
  6. mysql优化--叶金荣老师讲座笔记
  7. 大会门票限免最后一周!来聊聊 NVIDIA、抖音等大厂的 AI 技术落地
  8. python--二叉树库函数
  9. Android下图片处理的的一些方法
  10. 独家 | 一文读懂Adaboost
  11. 国内搜索大哥iOS面试题
  12. 【汇编语言】,值得学习的“编程世界的常青树”
  13. 解决Visual Studio 2015创建工程时的“DNX SDK version 'dnx-clr-win-x86.1.0.0-beta5' failed to install.”错误...
  14. 实现线程的方式,源码分析:Runnable, Thread, Callable, Future, FutureTask
  15. 文章整理 - 匠人精神
  16. 人脸关键点检测原理及实战
  17. windows 实现 linux soft link,Linux中的软链接(Soft Link)和硬链接(Hard Link)的区别...
  18. php中alight是什么意思,进阶PHP需要注意的一些点
  19. PPT修行之路(二)-素材库
  20. 固态硬盘打开计算机就死机,SSD固态硬盘死机卡顿无响应怎么办?SSD卡顿故障处理教程 | 麦田一棵葱...

热门文章

  1. flutter scrollview_简单易上手的Flutter学习指南App,2020一起来玩转Flutter吧~
  2. axure怎么做手机app界面_iPhone11手机APP频繁闪退怎么办?
  3. unity 安卓 后台运行_iOS14多任务界面放出,类似iPad,实现安卓锁定后台的功能?...
  4. layui移动端适配_移动端适配方案
  5. php oracle 锁表,频繁使用的一张表经常好被锁死?怎样处理!
  6. mysql大量重复值建立索引_对于有大量重复数据的表添加唯一索引
  7. ib课程计算机科学内容,新的IB计算机课程主要学习什么内容?有什么新的特点呢?...
  8. linux中postscript如何生成,【转载】如何为Linux生成和打上patch
  9. html超链接打开共享文件夹,教你如何访问共享文件夹
  10. php warning date(),lnmp打开cacti时提示PHP Warning: date()