Dagger2的使用说起来并不难,关键在于要掌握Dagger2的提供的几个注解及其意思。
在模块级的build.gradle文件中加入如下依赖:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
namespace 'com.example.test'
compileSdk 32
defaultConfig {
applicationId "com.example.test"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility 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语言需要使用kapt
kapt '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.test
class 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.test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
class 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呢?牢记下面几个步骤即可:
package com.example.test
import dagger.Module
import dagger.Provides
@Module
class StudentModule {
@Provides//如果不使用该注解,dagger框架就不知道如何new出Student对象了
fun getStudnet():Student{
return Student()
}
}
package com.example.test
import android.app.Activity
import dagger.Component
@Component(modules = [StudentModule::class])
interface StudentComponent {
//易错点:1.必须要要有一个注入地点的参数,例如:我们想要注入到StudentManager中,那么必须传该类的参数
//2.参数类型必须是本类,不能是其父类
//不符合上面两点,都是会报空指针异常的
fun injectActivity(activity: MainActivity)//返回值必须是void
fun inject(str:StudentManager)
}
package com.example.test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject
lateinit var student:Student
override 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 {
@Inject
public 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;
}
@Override
public void injectActivity(MainActivity activity) {
injectMainActivity(activity);
}
@Override
public 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);
}
@Override
public 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;
}
@Override
public 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、反射、设计模式等这些基础的知识。因此,学好基础是十分重要嘀。。。