近日谷歌母公司Alphabet股价大幅上涨。公司股价收盘上涨近2%,盘中一度涨逾2.5%,至每股828.81美元,创下谷歌在2004年8月上市以来的最高纪录。相关人士分析,Alphabet公司股价大涨,主要得益于本月初推出的Pixel系列新款手机广受好评。Pixel 最大杀手锏是可以令 iPhone 用户轻松将数据转换到谷歌手机的安卓系统中,并且在拍照效果上要好于iPhone 7。
本篇来自
study_zhxu
的第二篇投稿,之前他已经给大家分析过MVP模式,今天他将分享如何使用Dagger2,并给出自己的理解。最后祝大家周末愉快!
study_zhxu
的博客地址:
http://blog.csdn.net/study_zhxu
现在
Dagger2
在项目中的使用越来越多,
Dagger2
是 Dagger 的升级版本,Dagger 没有使用过,但是本篇说的是
Dagger2
,主要讲解的是
Dagger2
是如何使用的。对了,忘了说 Dagger 其实是一个
依赖注入
的框架。
依赖注入
是一种
面向对象
的编程模式,它的出现是为了
降低耦合性
,所谓
耦合
就是
类之间依赖关系
,所谓降低耦合就是降低类和类之间依赖关系。
可能有的人说自己之前并没有使用过依赖注入,其实真的没有使用过吗?当我们在
一个类的构造函数中通过参数引入另一个类的对象
,或者
通过set方法设置一个类的对象
其实就是使用的依赖注入。
public
class ClassA {
ClassB classB;
public void setClassB(ClassB b) {
classB = b;
}
}
public class ClassA {
ClassB classB;
public void ClassA(ClassB b) {
classB = b;
}
}
public class ClassA {
//此时并不会完成注入,
//还需要依赖注入框架的支持,如Dagger2
@inject
ClassB classB;
public ClassA() {}
}
下面我们就来说说如何通过
Dagger2
来实现
依赖注入
吧。
添加apt插件
添加依赖(在build.gradle中添加如下代码)
添加完 Dagger 的依赖后我们如何在项目中使用 Dagger 呢?
在项目中绝大多数的使用都是
Dagger
结合
MVP架构
使用的,在
MVP
中使用是非常典型的降低耦合的使用。
本篇文章中的示例是一个简单的登陆功能的示例,该示例采用
MVP架构
设计通过
Dagger2
进行解耦合,下面就来看看如何使用吧。
在使用
Dagger2
前我们最好简单的了解一下MVP,主要是为了理解本篇中的代码。简单了解 MVP 即使不会写 MVP 也可以看的懂本篇的代码。
为什么要选择在
MVP模式
中使用
Dagger2
呢?因为在
MVP模式
中
Activity
持有
presenter
的引用,同时
presenter
也持有
view
的引用,这样便于更新UI界面,这样
Activity
就和
presenter
仅仅的耦合在一起了,而
Dagger2
是依赖注入框架就是解耦合的,所以
MVP
中使用
Dagger2
也就再好不过了。
我们看如下代码:
在上述代码中可以看到
activity
持有了
presenter
的引用并且创建了该对象,但是如果
presenter
的构造函数发生改变则这里也需要改变,其实所有和
presenter
构造函数相关的代码都要改变。
但是如果我们使用
Dagger2
依赖框架该如何使用呢?请看下面代码:
activity
中的代码:
LoginPresenterCompl
中的代码:
只有上述两个注解还无法完成依赖注入,还需要如下两个新增类:
新增的
MainModule
类:
@Module
public class MainModule {
private final ILoginView view;
public MainModule(ILoginView view){
this.view = view ;
}
@Provides
ILoginView provideILogView(){
return view ;
}
}
新增的
MainComponent
接口:
@Component(modules = MainModule.class)
public
interface MainComponent {
public void inject(LoginActivity activity) ;
}
通过 直接注解 和 上述两个接口类 即可完成
Dagger2
的依赖注入。
在
LoginActivity
中是通过:
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
完成依赖注入的。
看完上面的代码后,一脸的懵逼,WTF(what the fuck),这TM是什么,这么复杂,还不如之前的简单呢,新增了两个类还有这么多代码,得不偿失呀!
同志们,如果你们第一眼看到后是这样想的话,说明和我想的一样,呵呵。每一个刚接触
Dagger2
的人可能都会这样想,因为我们只看到了表面。
不错,表面上我们是多了一个类和接口也多了很多代码,但是这样的组合其实是可以理解的。因为通常简单的代码具有耦合性,而要想降低这样的耦合就需要其他的辅助代码,其实少代码量和低耦合这两者并不能同时兼顾,古人云:鱼和熊掌不可兼得。我们作为堂堂聪明绝顶的程序猿怎么可能会输给古人呢。
好!下面来认真讲解
Dagger2
是如何完成依赖注入的。
首先我们来看看
LoginActivity
代码,
LoginActivity
中有这么一段代码:
@Inject
LoginPresenterCompl loginPresenter;
同样在
LoginPresenterCompl
中也有这么一段代码:
@Inject
public LoginPresenterCompl(ILoginView view){
loginView = view ;
user = new User("张三","123456") ;
}
之所以挑出这两段代码是因为它们都添加了
@Inject注解
。
在
LoginActivity
中其实只有这么一句提到
loginPresenter
,在接下来的代码中并没有对其进行初始化。
那
loginPresenter
是如何进行初始化的呢(此处注意添加
@Inject注解
的变量不能被
private
修饰)?
直观上我们可以这样理解,被
@Inject
注解的代码存在某种联系,当代码执行到
@Inject
的时候程序会自动进入到这个类的构造方法中,如果正巧这个构造方法也被
@Inject
修饰了,那么系统就会帮我们自动创建对象。
这只是表面的理解,这其中肯定还有很多我们没有看到的“猫腻”。这俩不会无缘无故的有联系,肯定还有第三者,通过这个第三者这两个被
@Inject
注解修饰的代码才会产生联系。
这个第三者是谁呢?自然的我们就会想到我们添加的这个 类 和 接口。
首先我们来分析
MainComponent
接口,
代码如下:
@Component(modules = MainModule.class)
public interface MainComponent {
public void inject(LoginActivity activity) ;
}
MainComponent
是一个接口(也可以是一个抽象类),在这个接口中我们定义了一个
inject()
方法,其中参数是
LoginActivity对象
,同时
MainComponent
还被
@Component
注解着,注解中
modules
的值是
MainModule.class
,这个内容会在接下来的地方进行说明,暂时先放一放。
此时在 Android Studio 中,如果我们 rebuild 的一下项目就会有新的发现。在项目的
build/generated/source/apt/debug/项目包名/dragger
目录下生成对应的包其中包含
DaggerMainComponent
类,这个类名其实不是固定的,是根据我们上面写的
MainComponent
,加了
Dagger
前缀生成的
DaggerMainComponent
。其实在这个时候我们就已经完成了
present
的依赖注入。
但是在:
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
中我们看到还有一个
MainModule
,这个是我们自己创建的一个类,
MainModule
代码如下:
@Module
public class MainModule {
private final ILoginView view;
public MainModule(ILoginView view){
this.view = view ;
}
@Provides
ILoginView provideILogView(){
return view ;
}
}
我们可以看到这个类被
@Module
注解修饰,内部有一个
ILoginView
的变量和一个构造方法还有一个被
@Provides
修饰的
provideILogView
方法。
看到这还是一脸懵逼,这个类是干嘛的?
在
MainComponent
接口中我们看到这么一个注解
@Component(modules = MainModule.class)
,这里用到了
MainModule
,可见
MainComponent
需要
MainModule
一起才能完成工作。
其实这个类我们可以理解成提供参数的,也就是提供参数依赖的,如何理解呢?
在
MainModule
中我们为什么要提供
ILoginView
类型的对象?为什么不是其他的呢?
这是因为
LoginPresenterCompl
的构造函数需要这么一个参数,所以我们在这里提供这么一个相同的参数,并通过被
@Provides
注解修饰的方法将其返回出去,如果
LoginPresenterCompl
还需要其他的参数,同样我们也可以在这里添加对应类型的参数然后通过另一个被
@Provides
注解修饰的方法返回出去。
在
MainComponent
接口中提供的
inject()
方法的参数是
LoginActivity
,这个参数的含义是
LoginPresenter
要在什么地方注入。
了解了各个类的功能后我们来总结一下:
-
@Inject
程序会将 Dagger2 会将带有此注解的变量或者构造方法参与到依赖注入当中,Dagger2 会实例化这个对象。
-
@Module
带有该注解的类需要对外提供依赖,其实就是提供实例化需要的参数,Dagger2 在实例化的过程中发现一些参数,Dagger2 就会到该类中寻找带有
@Provides
注解的以
provide
开头的需找对应的参数。
-
@Component
带有该注解的接口或抽象类起到一个关联桥梁的作用,作用就是将带有
@Inject
的方法或对象和带有
@Module
的类进行关联,只有通过该接口或抽象类才可以在实例化的时候到带有
@Module
中类中去寻找需要的参数,也就是依赖注入。
OK,下面我们来捋捋思路。
1.
在这个示例代码中,
LoginActivity
中需要
LoginPresenterCompl
,所以在
LoginActivity
中定义了该对象并且通过
@Inject
将其注解,同时到
LoginPresenterCompl
的构造方法中也通过
@Inject
将其注解, 表明这些是需要依赖注入的。
2.
因为在
LoginPresenterCompl
的构造方法需要
ILoginView
类型的参数,所以需要通过依赖将获取这些参数,所以就需要带有
@Module
注解的类用于获取需要的参数,在
@Module
注解的类中通过被
@Provides
注解的以
provide
开头的方法对外提供需要的参数,一般而言有几个参数就需要有几个带有
@Provides
的方法。
3.
此时还需要一个桥梁将两者联系到一起,带有
@Component
的接口或抽象类就起到这个桥梁的作用。注解中有一个
module
的值,这个值指向需要依赖的
Module
类,同时其中有一个抽象方法
inject()
,其中的参数就是我们需要在哪个类中实例化
LoginPreserentCompl
,因为我们需要在
LoginActivity
中实例化,所以参数类型就是
LoginActivity
类型。
然后在 Android studio 中 rebuild 我们的项目,就会生成
DaggerMainComponent
类,通过:
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);
完成我们需要的依赖注入。
如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击
“投稿”
菜单查看。
欢迎
长按下图 -> 识别图中二维码
或者
扫一扫
关注我的公众号: