Dagger2
是由谷歌开源的依赖注入框架,主要用于 Java
以及 Android
的依赖管理。
它是在编译期间完成依赖的注入,性能和效率都非常高,不会产生额外的负担。
1.1 前提条件
-
Android Studio
:建议使用最新4.0
版本,体验飞一般的开发速度 -
Android Application
:通过Android Studio
创建的Empty Activity
工程 -
Dagger2 Dependencies
:富有冒险精神的开发者通常使用当前最新版本——2.28
1.1.1 Android Studio
尽管是谷歌家推出的 IDE
,但还是喜欢 JetBrains
系列全家桶。
所以先下载一个工具箱,然后通过它管理 Android Studio
版本的升降级。
下载地址:https://www.jetbrains.com/toolbox-app/。
工具箱界面:

1.1.2 Android Application
执行步骤(二选一):
- 打开全新的
Android Studio
>>Start a new Android Studio project
>> 按照下图选择 >>Next
- 从已打开的
Android Studio
>>New
>>>New Project
>>> 按照下图选择 >>Next

Next
之后:
- 输入
Name
即应用名称 - 输入
Package name
即包名 - 选择
Language
即开发语言 - 选择
Minimum SDK
即系统API
版本 - 点击
Finish
即完成项目的创建
1.1.3 Dagger2 Dependencies
点击右边的链接,可以查看 Dagger2
依赖的相关信息:Dagger2 For Maven Center。
1.2 由浅入深
本节内容仅涉及 @Inject
的最简单使用,由浅入深才能掌握精髓。
1.2.1 添加依赖
打开 app
模块的 build.gradle
文件,添加如下内容:
// Add Dagger dependencies
dependencies {
// other dependencies
api 'com.google.dagger:dagger:2.28'
annotationProcessor 'com.google.dagger:dagger-compiler:2.28'
}
随后 Sync Now
一下,完成依赖的自动下载。

1.2.2 构造注入
现在我们创建一个最简单的 Account
类:
import javax.inject.Inject;
public class Account {
public String username;
public String password;
@Inject
public Account() {
}
}
解释:关于 @Inject
注解,这是 JSR330 的特性,即标记注入实例,用在构造函数、方法和字段上。

1.2.3 实例工厂类
使用 Ctrl + F9
编译后,在 app\build\generated\ap_generated_sources\debug\out
目录下可以找到编译出来的类文件。

它的内容如下:
import dagger.internal.Factory;
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class Account_Factory implements Factory<Account> {
@Override
public Account get() {
return newInstance();
}
public static Account_Factory create() {
return InstanceHolder.INSTANCE;
}
public static Account newInstance() {
return new Account();
}
private static final class InstanceHolder {
private static final Account_Factory INSTANCE = new Account_Factory();
}
}
这就是一个简单的 单例模式 + 工厂模式 的实例工厂类。
1.2.4 依赖注入
我们在 MainActivity
中注入 Account
试试:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
@Inject Account account;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
不同于 Spring Framework
的 IoC
容器,对于实例字段来说, Dagger2
只能在非 private
级别上进行注入,除非你在构造函数或者方法上进行注入,才可以将字段声明为 private
的可见性,但对于 Android
的 Activity
,实例由系统创建,不适合构造函数的注入方式,所以这里声明为默认级别的可见性。
1.2.5 成员注入器
继续查看编译后的文件夹:

内容如下:
import dagger.MembersInjector;
import dagger.internal.InjectedFieldSignature;
import javax.inject.Provider;
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<Account> accountProvider;
public MainActivity_MembersInjector(Provider<Account> accountProvider) {
this.accountProvider = accountProvider;
}
public static MembersInjector<MainActivity> create(Provider<Account> accountProvider) {
return new MainActivity_MembersInjector(accountProvider);}
@Override
public void injectMembers(MainActivity instance) {
injectAccount(instance, accountProvider.get());
}
@InjectedFieldSignature("com.github.mrzhqiang.dagger2_example.MainActivity.account")
public static void injectAccount(MainActivity instance, Account account) {
instance.account = account;
}
}
从命名上来看,这是一个 MainActivity
的成员注入器,它实现了成员注入接口,并且可以看到 Account
的实例有被赋值到 MainActivity
中,它是通过 Provider<T>
这个接口来提供 Account
的实例。
1.3 运行
我们通过运行来检验一下,实例是否注入成功。
首先,修改 Account
的构造函数,并重写 toString
方法:
import androidx.annotation.NonNull;
import javax.inject.Inject;
public class Account {
public String username;
public String password;
@Inject
public Account() {
this.username = "fssd";
this.password = "123456";
}
@NonNull
@Override public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
提示:使用 Alt
+ Insert
快捷键,可以生成如 Getter and Setter
、equals and hashCode
和 toString
等方法。
然后,在 app\src\main\res\layout\activity_main.xml
中,添加 TextView
的 id
,以便通过 findViewById
找到组件的实例。
<TextView
android:id="@+id/content_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
最后,我们在 MainActivity
的 onCreate
方法中,找到 content_text
的实例,并让它来显示 Account
的字符串内容。
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
@Inject
Account account;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView contentText = findViewById(R.id.content_text);
contentText.setText(account.toString());
}
}
现在我们 Run
一下看看效果:

出现了意料之中的闪退现象,这说明依赖注入没有生效。
1.4 总结
当 @Inect
注解在实例的构造函数上时,会生成一个 实例工厂类。
当 @Inect
注解在实例的字段上时,会生成一个 成员注入器。
仅使用 @Inject
注解,依赖注入不能生效,调用实例时,还是会抛出 NPE
异常。
下一章,我们将从 Dagger2
中寻找解决办法。
网友评论