使用

Dagger2的使用说起来并不难,关键在于要掌握Dagger2的提供的几个注解及其意思。

环境搭建

在模块级的build.gradle文件中加入如下依赖:

plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'id 'kotlin-kapt'
}android {namespace 'com.example.test'compileSdk 32defaultConfig {applicationId "com.example.test"minSdk 21targetSdk 32versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}
}dependencies {implementation 'androidx.core:core-ktx:1.7.0'implementation 'androidx.appcompat:appcompat:1.4.1'implementation 'com.google.android.material:material:1.5.0'implementation 'androidx.constraintlayout:constraintlayout:2.1.3'//dagger2依赖implementation 'com.google.dagger:dagger:2.44.2'annotationProcessor 'com.google.dagger:dagger-compiler:2.44.2'//看到这句话,毫无疑问,dagger2使用apt技术//kotlin语言需要使用kaptkapt 'com.google.dagger:dagger-compiler:2.44.2'
}

注解

  • @Inject
    如果在类上添加此依赖注入,Dagger 就会构造一个这个类的实例并满足他们的依赖。
    通过这个inject注解可以将依赖需求方对象送到Component类中,Component类就会根据依赖需求方对象中声明的依赖关系来注入依赖需求方对象中所需要的对象,注意:inject方法的参数不能用父类来接收,@Inject注解的字段不能是private和protected的。

  • @Module
    编写Module类时要在该类上声明@Module以表明该类是Module类,这样Dagger2才能识别,Modules 类里面的方法专门提供依赖,如返回你需要依赖的对象实例。

  • @Provide
    在 modules 中我们定义的方法就用@Provide注解,作用是声明Module类中哪些方法是用来提供依赖对象的,当Component类需要依赖对象时,他就会根据返回值的类型来在有@Provides注解的方法中选择调用哪个方法。

  • @Singleton
    实现单例

  • @Component
    Components 从根本上来说就是一个注入器,也可以说是@Inject 和@Module 的桥梁,来连接@Inject 和@Module这两个部分。但@Component注解的作用可不是单单用来声明Component类,@Component注解有modules和dependencies两个属性,这两个属性的类型都是Class数组,modules的作用就是声明该Component含有哪几个Module;而dependencies属性则是声明Component类的依赖关系。

可能大家现在不太清楚上面几个注解的作用,看下面几个案例大家就知道了。

案例:正常情况下,如果我们想在要一个类中使用另一个类的对象,肯定需要new一下吧。

package com.example.testclass Student {}
package com.example.test;public class StudentManager {private Student student;private static StudentManager manager;public StudentManager(){student = new Student();}public static StudentManager getManager(){if(manager==null){manager = new StudentManager();}return manager;}public Student getStudent(){return student;}
}
package com.example.testimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toastclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)Toast.makeText(this,"hashcod is ${StudentManager.getManager().student.hashCode()}",Toast.LENGTH_LONG).show()}
}

在上例中,我们在StudentManager 类中new了一个Student的对象,这样我们在MainActivity中才能调用student类的hashcode方法,否则分分钟就会报空指针异常。那么有没有可能我们不需要在StudentManager类中new出Student对象,而student自动被初始化呢?Dagger2其实就是替我们完成这个初始化的步骤。也就是我们常说的“依赖注入”—>顾名思义,依赖Dagger2帮我们new出Student对象,然后注入到StudentManager中去。
那么,我们该如何使用Dagger2呢?牢记下面几个步骤即可:

  1. 将你要注入的对象放入一个Module类当中,该Module类必须被Module注解注释,同时要提供一个被Provides注解注释方法,获取注入对象的实例。什么意思呢?以下面的案例为例,我们要注入的对象是Student类,那么我们提供一个StudentModule类,然后在getStudnet方法中new出Student对象。
package com.example.testimport dagger.Module
import dagger.Provides@Module
class StudentModule {@Provides//如果不使用该注解,dagger框架就不知道如何new出Student对象了fun getStudnet():Student{return Student()}
}
  1. 新建一个接口类,使用Component注解注释,这样dagger2的注解处理器会帮助我们生成一个DaggerStudentComponent方法
package com.example.testimport android.app.Activity
import dagger.Component@Component(modules = [StudentModule::class])
interface StudentComponent {//易错点:1.必须要要有一个注入地点的参数,例如:我们想要注入到StudentManager中,那么必须传该类的参数
//2.参数类型必须是本类,不能是其父类
//不符合上面两点,都是会报空指针异常的fun injectActivity(activity: MainActivity)//返回值必须是voidfun inject(str:StudentManager)
}
  1. 在需要注入的地方使用inject注解和DaggerStudentComponent类
package com.example.testimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import javax.inject.Injectclass MainActivity : AppCompatActivity() {@Injectlateinit var student:Studentoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)DaggerStudentComponent.create().injectActivity(this)Toast.makeText(this,"hashcode is ${student.hashCode()}",Toast.LENGTH_LONG).show()Toast.makeText(this,"hashcod is ${StudentManager.getManager().student.hashCode()}",Toast.LENGTH_LONG).show()}val verticalGradientBrush = Brush.verticalGradient(colors = listOf(Color.Red,Color.Yellow,Color.White))
}

这样即可使用dagger2框架帮助我们自动初始化对象。
现在,我们有一个疑问,在Android中如果不是四大组件,只是一个普通的类能不能使用dagger2呢?答案是可以的。例如:我们在StudentMananger中初始化Student类。

package com.example.test;import javax.inject.Inject;public class StudentManager {@Injectpublic Student student;private static StudentManager manager;public StudentManager(){//        Activity activity;DaggerStudentComponent.create().inject(this);
//        student = new Student();}public static StudentManager getManager(){if(manager==null){manager = new StudentManager();}return manager;}public Student getStudent(){return student;}
}

原理分析

dagger2的用法我们明白了之后,接下来我们来分析下dagger2的原理。首先入手的地方肯定就是DaggerStudentComponent这个类了。代码比较简短,笔者就直接copy过来分析了。DaggerStudentComponent这个类是怎么来的呢?当我们使用Component注解时,注解处理器会自动帮我们生成。这块大家可以查阅dagger2的源码。我们调用了create方法之后就会生成StudentComponentImpl类,该类实现了我们定义的StudentComponent接口。因此,我们调用的inject方法或injectActivity方法,其实都是调用了StudentComponentImpl类中的方法。接下来,我们具体看看StudentComponentImpl中的方法都做了什么事情。

// Generated by Dagger (https://dagger.dev).
package com.example.test;import dagger.internal.DaggerGenerated;
import dagger.internal.Preconditions;@DaggerGenerated
@SuppressWarnings({"unchecked","rawtypes"
})
public final class DaggerStudentComponent {private DaggerStudentComponent() {}public static Builder builder() {return new Builder();}public static StudentComponent create() {return new Builder().build();}public static final class Builder {private StudentModule studentModule;private Builder() {}public Builder studentModule(StudentModule studentModule) {this.studentModule = Preconditions.checkNotNull(studentModule);return this;}public StudentComponent build() {if (studentModule == null) {this.studentModule = new StudentModule();}return new StudentComponentImpl(studentModule);}}private static final class StudentComponentImpl implements StudentComponent {private final StudentModule studentModule;private final StudentComponentImpl studentComponentImpl = this;private StudentComponentImpl(StudentModule studentModuleParam) {this.studentModule = studentModuleParam;}@Overridepublic void injectActivity(MainActivity activity) {injectMainActivity(activity);}@Overridepublic void inject(StudentManager str) {injectStudentManager(str);}private MainActivity injectMainActivity(MainActivity instance) {MainActivity_MembersInjector.injectStudent(instance, StudentModule_GetStudnetFactory.getStudnet(studentModule));return instance;}private StudentManager injectStudentManager(StudentManager instance) {StudentManager_MembersInjector.injectStudent(instance, StudentModule_GetStudnetFactory.getStudnet(studentModule));return instance;}}
}

我们分析下injectMainActivity这个方法,injectStudentManager是一样的逻辑。MainActivity_MembersInjector这个类和StudentModule_GetStudnetFactory这个类,自然也是inject和module注解通过注解处理器帮我们生成。

// Generated by Dagger (https://dagger.dev).
package com.example.test;import dagger.MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.InjectedFieldSignature;
import dagger.internal.QualifierMetadata;
import javax.inject.Provider;@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({"unchecked","rawtypes"
})
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {private final Provider<Student> studentProvider;public MainActivity_MembersInjector(Provider<Student> studentProvider) {this.studentProvider = studentProvider;}public static MembersInjector<MainActivity> create(Provider<Student> studentProvider) {return new MainActivity_MembersInjector(studentProvider);}@Overridepublic void injectMembers(MainActivity instance) {injectStudent(instance, studentProvider.get());}@InjectedFieldSignature("com.example.test.MainActivity.student")//这里,终于明白为什么我们需要传入该类的对象过来了,不然怎么为其赋值呢?public static void injectStudent(MainActivity instance, Student student) {instance.student = student;}
}

这个类,没什么好说的就是提供Student对象而已。

// Generated by Dagger (https://dagger.dev).
package com.example.test;import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.Preconditions;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;@ScopeMetadata
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({"unchecked","rawtypes"
})
public final class StudentModule_GetStudnetFactory implements Factory<Student> {private final StudentModule module;public StudentModule_GetStudnetFactory(StudentModule module) {this.module = module;}@Overridepublic Student get() {return getStudnet(module);}public static StudentModule_GetStudnetFactory create(StudentModule module) {return new StudentModule_GetStudnetFactory(module);}public static Student getStudnet(StudentModule instance) {return Preconditions.checkNotNullFromProvides(instance.getStudnet());}
}

至此,我们的源码分析到此结束。至于,apt生成代码这块有兴趣的大家可以自行分析。掌握apt注解处理器的知识,看源码就会比较容易,没有掌握的读者也不用担心,可以参考笔者之前的一篇博客:APT和Javapoet的精彩联动
其实,很多高大上的框架,它的底层技术貌似都是apt、泛型、asm、反射、设计模式等这些基础的知识。因此,学好基础是十分重要嘀。。。

参考资料

Dagger2的简单使用

Dagger2的使用以及原理分析相关推荐

  1. java signature 性能_Java常见bean mapper的性能及原理分析

    背景 在分层的代码架构中,层与层之间的对象避免不了要做很多转换.赋值等操作,这些操作重复且繁琐,于是乎催生出很多工具来优雅,高效地完成这个操作,有BeanUtils.BeanCopier.Dozer. ...

  2. Select函数实现原理分析

    转载自 http://blog.chinaunix.net/uid-20643761-id-1594860.html select需要驱动程序的支持,驱动程序实现fops内的poll函数.select ...

  3. spring ioc原理分析

    spring ioc原理分析 spring ioc 的概念 简单工厂方法 spirng ioc实现原理 spring ioc的概念 ioc: 控制反转 将对象的创建由spring管理.比如,我们以前用 ...

  4. 一次 SQL 查询优化原理分析(900W+ 数据,从 17s 到 300ms)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:Muscleape jianshu.com/p/0768eb ...

  5. 原理分析_变色近视眼镜原理分析

    随着眼镜的发展,眼镜的外型变得越来越好看,并且眼镜的颜色也变得多姿多彩,让佩戴眼镜的你变得越来越时尚.变色近视眼镜就是由此产生的新型眼镜.变色镜可以随着阳光的强弱变换不同的色彩. 变色眼镜的原理分析 ...

  6. jieba分词_从语言模型原理分析如何jieba更细粒度的分词

    jieba分词是作中文分词常用的一种工具,之前也记录过源码及原理学习.但有的时候发现分词的结果并不是自己最想要的.比如分词"重庆邮电大学",使用精确模式+HMM分词结果是[&quo ...

  7. EJB调用原理分析 (飞茂EJB)

    EJB调用原理分析 EJB调用原理分析 作者:robbin (MSN:robbin_fan AT hotmail DOT com) 版权声明:本文严禁转载,如有转载请求,请和作者联系 一个远程对象至少 ...

  8. 深入掌握Java技术 EJB调用原理分析

      深入掌握Java技术 EJB调用原理分析     一个远程对象至少要包括4个class文件:远程对象:远程对象的接口:实现远程接口的对象的stub:对象的skeleton这4个class文件. 在 ...

  9. 神经网络(NN)+反向传播算法(Backpropagation/BP)+交叉熵+softmax原理分析

    神经网络如何利用反向传播算法进行参数更新,加入交叉熵和softmax又会如何变化? 其中的数学原理分析:请点击这里. 转载于:https://www.cnblogs.com/code-wangjun/ ...

最新文章

  1. python快乐编程—基础入门-Python零基础快乐学习之旅(K12实战训练)
  2. 对三层架构的简单改进
  3. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170410
  4. Python中的支持向量机SVM的使用(有实例项目给的地址)
  5. 全网最新Spring Boot2.5.1整合Activiti5.22.0企业实战教程<入门篇>
  6. Metatdata分析
  7. 基于51单片机的密码锁
  8. silverlight安装后网页_纯干货收藏|两个技巧教你完美长截屏网页!
  9. Dos window下运行java程序
  10. Blue Prism宣布融资1亿英镑,创始人兼首席执行官宣布离职
  11. 轻松搞定个人虚拟桌面部署之5-在客户端测试远程桌面
  12. JS实现随机切换姓名与头像
  13. Keil C51 Code Banking
  14. 几种免杀转储lsass进程的技巧
  15. 计算机专业排名2017教育部,软件工程专业大学排名最新版(教育部2017学科排名数据整理)...
  16. 【通識:人生哲學與幸福】老子人生觀巡禮
  17. 如何将pdf文件转换成word格式
  18. 个人博客的Travis持续集成之路
  19. postgresql 10 的并行(parallel)简介
  20. canvas漫天闪烁的星星

热门文章

  1. 用 Python 写了一个天天酷跑(附源码)
  2. 刺激却安全,普通人也能体验的方程式赛车
  3. 计算机在电影特技中的应用,计算机3D技术在电影中的应用.doc
  4. IOS UITableView 实现LOL数据展示
  5. VB中的SQL语言——增、删、改、查
  6. PAT 1004 成绩排名 (20 分)
  7. Matlab绘制三维曲面(以二维高斯函数为例)
  8. 阿里云如何解析域名,阿里云域名解析最新教程
  9. 【教学类-12-10】20230316《连连看竖版6*6 (3套题目空心图案)(中班主题《玩具总动员》)
  10. pythonocc 保存为图片