今天玩一下Dagger2,个人第一感觉就是,一种本来挺好理解的东西,硬生生被玩着复杂和变得难以理解了,哈哈,也有可能是自己技术水平不够,不说废话了,下面开始记录一下我的学习心得。
Dagger2,官方的说明是A fast dependency injector for Android and Java,翻译成国语就是“Android和Java的快速依赖注入器。”
一、什么是依赖注入
下面先看一个例子,比如我假设有一个类——Ferry(船),一个类——Paddle(桨),现在我们需要定义一个船类,并且在船类中定义一个变量桨类,我们会这样做:
class Ferry{
Paddle paddle = new Paddle();
Ferry();
}
上面这种写法很完美的解决问题,但是现在如果Ferry类的需求改了,需要加入一个参数,那么我们是不是要同时修改Ferry类和Paddle类,这样看来Ferry类是不是很依赖Paddle类,Paddle类一改,Ferry类就要跟改。那么我们的程序员就想出一个方法,不在Ferry类中新建Paddle类,而是在外面把Paddle类注入进入,比如这样:
class Ferry{
Paddle paddle;
Ferry(Paddle paddle){
this.paddle = paddle;
}
}
上面这种这种做法就是依赖注入,把所依赖的Paddle类从外面把它注入进来,而不是在Ferry类中自己建立。而Dagger2就是用来做上面依赖注入这一步的,他的基本原理就是这么简单,但是跟上面不同,他不是直接以构造方法的参数形式注入的,下面我会详细解释。
补充一下:依赖注入其实是一种方法,他的主要思想叫做控制反转(Inversion of Control,英文缩写为IoC),控制反转还有另一种方法叫做依赖查找,想了解详细的,自行百度。
二、环境搭建
怎么将Dagger2接入AS工程中,只需要两步:
1、在主工程下的build.gradle中加入classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
2、然后在app模块分别加入:
apply plugin: 'com.neenbedankt.android-apt'
compile ‘com.google.dagger:dagger:2.11’
apt‘com.google.dagger:dagger-compile:2.11’
provided ‘org.glassfish:javax.annotation:10.0-b28’
这样就完成Dagger2的Gradle配置,如果你是高版本的AS这样配置可能会出现问题,请参考我的另一篇博客
http://blog.csdn.net/m0_37605407/article/details/79091389
三、现在开始玩最简单的Dagger2
下面这些步骤都是基本固定,只要按照这样的步骤就可以实现Dagger2构架的接入。
我们接着上面船和桨的例子,用Dagger2实现依赖注入:
//船类
public class Paddle {
@Override
public String toString() {
return "我是船";
}
}
//Paddle的提供类
@Module
public class MainModule {
@Provides
public Paddle getPaddle() {
Paddle paddle = new Paddle();
return paddle;
}
}
//建立一个接口,连接Paddle类和Ferry类的关系
@Component(modules=MainModule.class)
public interface MainComponent {
void inject(FerryActivity ferryActivity);
}
然后编译,你会惊喜发现自动多了两个中间类。
现在可以在Ferry类中进行依赖注入了
public class FerryActivity extends AppCompatActivity {
@Inject
Paddle paddle;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainComponent build = DaggerMainComponent.builder().mainModule(new MainModule()).build(); //关键代码1
build.inject(this); //关键代码2
Log.d("Dagger2",paddle.toString() );
}
}
到这里就完成了整个步骤,可以成功打印出 03-21 23:18:18.918 28286-28286/? D/Dagger2: 我是船
我们开始从代码中去看Dagger2到底干些什么?
首先,在FerryActivity中调用关键代码1,新建了DaggerMainComponent类中的静态内部类Builder,然后把一个新建MainModule类传递给Builder,最后新建一个带有MainModule对象的DaggerMainComponent类
public static final class Builder {
private MainModule mainModule;
private Builder() {}
public MainComponent build() {
if (mainModule == null) {
this.mainModule = new MainModule();
}
return new DaggerMainComponent(this);//新建一个带有MainModule对象的DaggerMainComponent类
}
public Builder mainModule(MainModule mainModule) {
this.mainModule = Preconditions.checkNotNull(mainModule);//FerryActvity调用这个方法传递进去MainModule对象
return this;
}
}
然后,在DaggerMainComponent类的构造方法中
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);//在这步里面做了关键步骤
}
private void initialize(final Builder builder) {
this.getPaddleProvider = MainModule_GetPaddleFactory.create(builder.mainModule);
this.ferryActivityMembersInjector = FerryActivity_MembersInjector.create(getPaddleProvider);
}
我们先来看,this.getPaddleProvider = MainModule_GetPaddleFactory.create(builder.mainModule)这一步干了些什么?
public static Factory<Paddle> create(MainModule module) {
return new MainModule_GetPaddleFactory(module);
}
上面代码中,新建了MainModule_GetPaddleFactory对象,然后传递给了FerryActivity_MembersInjector的静态方法create。
public static MembersInjector<FerryActivity> create(Provider<Paddle> paddleProvider) {
return new FerryActivity_MembersInjector(paddleProvider);
}
上面代码中,新建了一个带有MainModule_GetPaddleFactory对象的FerryActivity_MembersInjector类。然后在FerryActivity中调用了关键代码2
调用了DaggerMainComponent类中的inject方法
@Override
public void inject(FerryActivity ferryActivity) {
ferryActivityMembersInjector.injectMembers(ferryActivity);
}
public void injectMembers(FerryActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.paddle = paddleProvider.get();
}
public Paddle get() {
return Preconditions.checkNotNull(
module.getPaddle(), "Cannot return null from a non-@Nullable @Provides method");
}
哈哈,到这里真相大白了,FerryActivity.paddle = Module.getPaddle,其实啊,弄了这么久,Dagger就是做了这么一件事情。
今天先到这里,上面的出现的一些注解,只是为了让apt编译出中间的类,但是对于这些注解的特殊用法,我还没有去深究,关于Dagger2的学习笔记我会在接下来的博客继续更新。