Dagger2 Android依赖注入学习笔记
作者:reggie1996 发布时间:2021-11-27 17:15:54
前言
最近在用 MVP + RxJava + Retrofit 写项目,觉得相对于其他的开发框架,这的确是给我们带来了很多方便,但是在网上搜寻相关资料的时候,总是能看到 MVP + RxJava + Retrofit + Dagger 这样的搭配组合,那 Dagger 又是一个怎样的框架呢,我也去具体搜了搜,但看到一些文章带着“Dagger2从入门到放弃”这样意思的句子,就感觉Dagger2会很难吗,emmmm...行吧,好像是有点难理解,但是想着既然有那么多人用这个框架,必然有它的好处,于是花了些时间学习了一波。
Dagger2
Dagger2 : A fast dependency injector for Android and Java. (官方给出的定义)
Dagger2是一个依赖注解框架,它的作用就是通过注解来实现组件之间的依赖,由此来达到更好的解耦,比如说,如果将 Dagger2 使用到我们的 MVP 框架中,那么我们就可以达到 V层 和 P层 的进一步解耦,从而使我们的项目有更好的维护性。
Dagger2 和 Butterknife 一样,都是在编译阶段利用Java注解通过APT(Annotation Processing Tool)自动生成Java代码,然后由我们自己写的代码进行调用,完成依赖注入,因此不用担心性能上的问题。那么如何来使用 Dagger2 呢?我们先来看一下使用 Dagger2 和不使用的区别。
对比
用简单的例子来说明。比如说我们有这样一个AAA类,没什么内容,只有一个get()方法
/**
* @author chaochaowu
* @Description : AAA
* @class : AAA
* @time Create at 6/12/2018 10:58 AM
*/
public class AAA {
public AAA() {
}
public void get(){
Log.e("AAA","has gotten.");
}
}
我们需要在MainActivity用到这个类,因此MainActivity中变含有这个成员变量,有了这个成员变量aaa,我们就要对它进行实例化,因此会有以下的代码:
/**
* @author chaochaowu
* @Description : MainActivity
* @class : MainActivity
* @time Create at 6/12/2018 10:58 AM
*/
public class MainActivity extends AppCompatActivity {
AAA aaa;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
aaa = new AAA();
aaa.get();
}
}
我们需要在 MainActivity 中声明aaa这个变量,然后会对其进行new一个实例,然后才能对其进行调用,调用它定义的方法。这样,AAA类对象的创建就和 MainActivity 耦合在了一起。如果使用 Dagger2 进行依赖注入呢
/**
* @author chaochaowu
* @Description : MainActivity
* @class : MainActivity
* @time Create at 6/12/2018 10:58 AM
*/
public class MainActivity extends AppCompatActivity {
@Inject
AAA aaa;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
DaggerMainActivityComponent.create().inject(this);
aaa.get();
}
}
代码就会变成这样。我们可以发现MainActivity里没有任何有关aaa的初始化赋值,但是它还是可以调用其get()方法。这样我们就达到了解耦合的目的。
这样一个简单的例子可能看不出 Dagger2 的好处,但是你可以想象一下,如果这个 Activity 里有很多个类似 AAA 这样的类的成员变量,它们都需要初始化,有的初始化还要传参数,那么,这个 Activity 就会变得臃肿,如果 AAA类 的初始化参数变了,不仅 AAA类 需要改,MainActivity 因为它与AAA类的耦合也要跟着改变,如果 AAA类 不止用在 MainActivity 中还用在了其他的 Activity 中,那么要改的东西变的可有点多咯,但是如果用上Dagger2,我们就可以很好的解决这个问题。
注解介绍
Dagger2中注解有:@Inject, @Component, @Module, @Provides, @Qulifier, @Scope, @Singleten 。而我们主要用到的是@Inject, @Component,@Module, @Provides 这四个,下面来介绍一下。
@Inject
Inject 主要用来标记需要依赖的变量,告诉Dagger需要为它提供依赖;inject 还被用来标记类的构造函数。当Dagger2碰到使用@Inject注解的变量时,会去寻找这个变量对应的被@Inject注解的构造函数,把实例构造出来,为变量提供依赖。
@Component
@Component用于标注接口,是依赖需求方(MainActivity)和依赖提供方(AAA)之间的桥梁。被Component标注的接口在编译时会生成该接口的实现类,类的名称为被@Component注解的类的名称前加上Dagger,我们通过调用这个实现类的方法来完成注入。
@Module
Module用于标注提供依赖的类。虽然我们有@Inject注解实现注入,但是@Inject只能注入构造函数为无参的类,要是构造函数是带参数的呢?那就要使用module注解来解决这个问题,又比如说,有很多的第三方库,我们对它的代码无法进行修改,也就不能对其构造函数加上@Inject注解,那么可咋办啊,@module注释可以很好的解决我们的问题。
@Provides
Provides是与Module一起使用的,@Provides用于标注Module所标注的类中的方法,该方法会在需要提供依赖时被调用,在方法内进行对象的初始化,返回对象依赖给标注了@Inject的变量。相当于一个有参数的@Inject。
我们来具体的使用一下。
构造函数无参的对象注入
用上面提到的 AAA类 进行依赖注入演示。
首先我们在 AAA类 的构造函数上加上 @Inject 注解(构造函数必须得是无参)
/**
* @author chaochaowu
* @Description : AAA
* @class : AAA
* @time Create at 6/12/2018 10:58 AM
*/
public class AAA {
@Inject
public AAA() {
}
public void get(){
Log.e("AAA","has gotten.");
}
}
然后创建一个 MainActivityComponent 接口并用 @Component 进行注解,然后Build一下项目,
/**
* @author chaochaowu
* @Description : MainActivityComponent
* @class : MainActivityComponent
* @time Create at 6/12/2018 11:03 AM
*/
@Component
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
Build之后apt会自动生成如下的代码
build后生成.png
我们利用其中的 DaggerMainActivityComponent 进行 MainActivity 与 AAA类 之间的桥梁搭建。如下代码
/**
* @author chaochaowu
* @Description : MainActivity
* @class : MainActivity
* @time Create at 6/12/2018 10:58 AM
*/
public class MainActivity extends AppCompatActivity {
@Inject
AAA aaa;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
DaggerMainActivityComponent.create().inject(this);
aaa.get();
}
}
至此,我们便完成了构造函数无参的对象的依赖注入。
构造函数含参的对象注入
相信很多的时候,我们要用的对象在构造的时候是需要参数的,那我们如何进行它们的依赖注入呢,这里我用 MVP 中的 Presenter 来进行演示。
/**
* @author chaochaowu
* @Description : MainActivity
* @class : MainActivity
* @time Create at 6/12/2018 10:58 AM
*/
public class MainActivity extends AppCompatActivity implements MainContract.View{
MainContract.Presenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter = new MainPresenter(this);
mPresenter.getData();
}
}
上面的代码是没用 Dagger2 时的 Activity,在 MVP 框架中,由于 Presenter 需要与 View 进行交互,需要持有View的对象,因此在初始化的时候,需要在构造函数里传入View对象作为参数,可以看到代码中 mPresenter = new MainPresenter(this);
接下来我们对它进行依赖注入。首先看一下 Presenter,,Presenter不需要作出任何改变,我们可以看到它的构造函数带有一个参数View
/**
* @author chaochaowu
* @Description : MainPresenter
* @class : MainPresenter
* @time Create at 6/11/2018 2:22 PM
*/
public class MainPresenter implements MainContract.Presenter{
MainContract.View mView;
public MainPresenter(MainContract.View mView) {
this.mView = mView;
}
@Override
public void getData() {
}
}
然后我们需要创建一个 MainActivityModule 类,并在该类名加上@Module注解,它含有一个成员变量 mView 需要在构造函数时赋值,我们之后会将这个变量给 Presenter 进行 Presenter 的构造,我们还需要写一个方法,并在其上添加@Provides注解,方法的名字其实没所谓可以随便取,但是为了代码的可读性,一般都以provide开头加上provide的东西的名字,我们在这个方法里返回我们所要提供依赖的对象,这里返回了一个 Presenter 对象,可以看到它在这里的构造,我们传入了参数 View。到这便完成了MainActivityModule 的定义,其实这个 MainActivityModule 作用就和之前的 构造函数无参中的 对无参构造函数 Inject 步骤的性质相同。
/**
* @author chaochaowu
* @Description : MainActivityModule
* @class : MainActivityModule
* @time Create at 6/11/2018 2:41 PM
*/
@Module
public class MainActivityModule {
MainContract.View mView;
public MainActivityModule(MainContract.View mView) {
this.mView = mView;
}
@Provides
public MainContract.Presenter providePresenter(){
return new MainPresenter(mView);
}
}
接下来和 构造函数无参的对象注入 中一样,我们需要定义一个 MainActivityComponent ,并用 @Component 进行注解,不一样的是需要在括号里加上参数 modules = {MainActivityModule.class} 如下代码。
/**
* @author chaochaowu
* @Description : MainActivityComponent
* @class : MainActivityComponent
* @time Create at 6/11/2018 2:45 PM
*/
@Component(modules = {MainActivityModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
Build一下项目
build之后生成.png
这样我们就可以像上面一样,在Activity中调用DaggerMainActivityComponent 进行依赖注入。看一下Activity中的代码。
/**
* @author chaochaowu
* @Description : MainActivity
* @class : MainActivity
* @time Create at 6/12/2018 10:58 AM
*/
public class MainActivity extends AppCompatActivity implements MainContract.View{
@Inject
MainContract.Presenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build()
.inject(this);
mPresenter.getData();
}
}
可以看到这里 DaggerMainActivityComponent 调用的方法有所不同,其中调用了一个mainActivityModule() 方法,传入了一个 MainActivityModule 对象,该对象的初始化,我们又传入了一个this,也就是View,这个 View就是我们在之后创建 Presenter 时传入的参数 。
至此,我们就完成了构造函数有参的对象的依赖注入。其他有参的、第三方库的依赖注入也是通过这样的方式进行。
总结
Dagger2的使用,让我们代码的耦合度进一步降低了,这是一个优点,但是另一方面,使用了Dagger2你需要额外的去定义一些类,导致代码的数量也增加。个人觉得,在比较小的项目中,如果去使用,有点emmmm....多此一举?(划掉),但是如果一个项目比较大,代码本身也比较多,那么使用Dagger2所带来的优点,便可以显现了。所以说,是否在项目中使用 Dagger2 仁者见仁智者见智,不过作为一个学习的点,还是挺不错的,嗯。
来源:https://www.jianshu.com/p/3e9862b61625
猜你喜欢
- PDF是一种在我们日常工作学习中最常用到的文档格式之一,但常常也会因为文档的不易编辑的特点,在遇到需要编辑PDF文档内容或者转换文件格式的情
- 文章开始之前,先看一下效果图,看是不是您正所需要的:一、构建计算器的界面要构建出一个好看点的计算器界面,还是需要颇费些小心思的,我做这个的时
- 一、WebSocket简介WebSocket协议通过在客户端和服务端之间提供全双工通信来进行Web和服务器的交互功能。在WebSocket应
- 引言委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易。它们就
- 一、理解slf4j(Simple Logging Facade for Java),表示为java提供的简单日志门面,更底层一点说就是接口。
- 以前一直使用Hibernate,基本上没用过Mybatis,工作中需要做映射关系,简单的了解下Mybatis的映射。两者相差不多都支持一对一
- 摘要 &n
- 在看内存管理术语表的时候偶然发现了”Pig in the Python(注:有点像中文里的贪心不足蛇吞象)”的定义,于是便有了这篇文章。表面
- 使用到Process和Runtime两个类,返回值通过Process类的getInputStream()方法获取package ark;im
- 转发和重定向相同点都是web开发中资源跳转的方式。不同点转发:是服务器内部的跳转,浏览器的地址栏不会发生变化。从一个页面到另一个页面的跳转还
- 先来说一说我们为什么要用这个东西啊!比如,我们现在有这样了个问题要解决:这样,我们就要用到中间消息间了然后我们就说一下什么是中间消息间吧。采
- 概念 在 HTML 中,<a>, <form>, <img>, <script>,
- 双色球选号规则红球是1~33选6个,蓝球1~16选1个。它有17721088种排列组合,这个代码实现了如何将一组双色球号码 转换成第n个排列
- 1.瞬时流量过高,服务被压垮?2.恶意用户高频光顾,导致服务器宕机?3.消息消费过快,导致数据库压力过大,性能下降甚至崩溃?......在高
- 本文实例为大家分享了C#实现扫雷游戏的具体代码,供大家参考,具体内容如下一、实验目的:1、掌握c#窗体和控件的常用属性和功能2、完成扫雷游戏
- 快速排序快速排序是对冒泡排序的一种改进,也是采用分治法的一个典型的应用。JDK中Arrays的sort()方法,具体的排序细节就是使用快速排
- 概念代理:为控制A对象,而创建出新B对象,由B对象代替执行A对象所有操作,称之为代理。一个代理体系建立涉及到3个参与角色:真实对象(A),代
- 面试题1:说说你对消息队列的理解,消息队列为了解决什么问题?我们公司业务系统一开始体量较小,很多组件都是单机版就足够,后来随着用户量逐渐扩大
- 从功能上说,可以分为两部分,分布式功能和数据功能。分布式功能主要是节点集群及集群附属功能如restful借口、集群性能检测功能等,数据功能主
- 示例 1 :使用搜索表单创建全屏模式我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮。按下此按钮时,将出现一个全屏模式对话框。它不