网上的Dagger2各种多,但看完了,只能让原本懵逼的更懵逼,我只能说大神的世界我不懂,那么Dagger2真那么难吗?给我耐心,我给你答案!!!
1.定义:没耐心了解的,也可以下一步。
Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier versioncreated by Square and now maintained by Google. Dagger aims to address many of the development and performance issues that have plagued reflection-based solutions. More details can be found in this talk(slides) by +Gregory Kick.
什么意思啊?高屋建瓴,一针见血,力透纸背,入木三分,高端大气上档次,
- Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,Dagger解决了基于反射带来的开发和性能上的问题(因为Dagger并没有用反射来做依赖注入)就是说它帮我们自动生成注入需要的代码,跟纯手写没区别,只是写这些机械的代码的过程Dagger2 代劳了。
2. 添加依赖
- Project级别bulid.gradle 添加classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8',如下
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
}
}
-
Module 级别 build.gradle 顶上位置加apply plugin: 'android-apt',dependencies 里加
provided 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.dagger:dagger:2.5'
apt 'com.google.dagger:dagger-compiler:2.5'
完成代码如下:apply plugin: 'com.android.application'
apply plugin: 'android-apt'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.zhang.testing.daggertest"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
//dagger2
provided 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.dagger:dagger:2.5'
apt 'com.google.dagger:dagger-compiler:2.5'
}
到这,我们就能在项目中使用Dagger2了
#### 3. 最简单的dagger2使用
这里是基于最简单的MVP模式的dagger2最简单使用。我们先看代码,这样效率高,容易理解。不信,follow me !!!
1. 新建一个类Prensenter(它的实例就是商品),,这个是要注入到MainActivity(MainActivity就是采购商)中的,不懂没事,接着往下看,**这里注意@Inject这个注解(相当于订单,Dagger2老司机就认这个)**
```
public class Presenter {
private MainActivity mMainActivity;
@Inject
public Presenter(MainActivity mainActivity) {
this.mMainActivity = mainActivity;
}
//下载数据的方法,这里只是模拟
public void loadData() {
System.out.println("下载中");
}
}
- 再新建个类MainActivityModule(这里比喻为一个仓库,用@Module表示)Module中有用@Provides注解的方法,就相当于仓库中的货架,可以对外提供商品。下面代码中的方法provideMainActivity()方法的返回是MainActivity,那么它提供的商品就是MainActivity的实例
/**
* Created by zyg on 2016/11/8.
*/
@(个人博客)Module
public class MainActivityModule {
private MainActivity mMainActivity;
public MainActivityModule(MainActivity activity) {
this.mMainActivity = activity;
}
@Provides
public MainActivity provideMainActivity(){
return mMainActivity;
}
}
- 再 新建接口 MainComponent,这个接口被@Component注解,表示它是个Component(供货商,交易商),在注解的后面的括号里,指明了modules= MainActivityModule.class,将Component 和Module 关联起来(就是说MainActivityModule这个仓库,是MainComponent这个供货商的仓库)
/**
* Created by zyg on 2016/11/8.
*/
@Component(modules = MainActivityModule.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
- 再看MainActivity方法,我们的目的就是将 Prensenter的实例注入到MainActivity中, 这里我们申明了Presenter mPresenter,并且在它的头上也有个@Inject标注(告诉老司机Dagger2这是我缺的货,快去给我从供货商那给我拉回来),然后rebuild工程,注入所需要的代码就会自动生成。然后我们再调用下面这些方法,完成最后的注入
DaggerMainComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build()
.inject(this);**
package com.zhang.testing.simplemvpdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.zhang.testing.simplemvpdemo.di.component.DaggerMainComponent;
import com.zhang.testing.simplemvpdemo.di.module.MainActivityModule;
import com.zhang.testing.simplemvpdemo.presenter.Presenter;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "daggerTest";
@Inject
Presenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build()
.inject(this);
}
//更新UI的操作
public void refeshUi() {
Log.d(TAG, "更新ui");
}
}
分析总结:到这里一个最简单的dagger2注入过程就完成了,我们把Presenter 的实例注入到MainActivity中,这时候我们就能调用Prensent 中的方法了。因为是Mvp模式,所以Prensenter类也需要拿到了MainActivity的实例,(至于怎么拿到的,少年莫急,一步一步慢慢来!)调用Prensent中的方法完成下载后,就可以调用MainActivity中的方法完成UI的更新。
- 下面我们分析下Dagger2老司机怎么把MainActivity这个采购商从供货商哪里采购到商品的
- 在MainActivity 中的@Inject注解告诉Dagger2这个货车老司机需要采购什么了,我缺什么货了,我缺Presenter类的实例(呵呵,Dagger2这个老司机只认识@Inject注解的订单)
- 然后Dagger2就会去和MainActivity相关的供货商Component去要,Component就会去和它关联的Module仓库中去找,但是打开仓库也是有条件的(管理比较严格),就是得有MainActivity的身份证(就是MainAcitivty的实例,,你理解成钱也好,身份证也罢,反正就是个凭证),Component在货架(@Provides注解的方法)中找了半天也没有,只发现提供MainAcivity的实例的货架。
- 于是Component 只能去找Presenter本人碰碰运气,运气还不错。Presenter中有@Inject注解的构造方法,这里可以提供。但是Presenter说你得给我提供一个 MainActivity的身份证(还是 MainActivity的实例),我才能给你new 一个Prensenter实例,巧了,刚在Module仓库的不是有提供 MainActivity的实例的货架?把MainActivity实例给了Presenter,Presenter就new了个实例给了Component,同时Prensenter也拿到了 Activity的实例。
- Component屁颠屁颠的跑回来和Dagger2老司机说,拿到Presenter实例了,但是你得提供MainActivity的身份证(MainActivity的实例)咱们签订合同,你就把Presenter的实例拉走,调用inject方法签订合同,Dagger2老司机就把货给MainActivity拉回来了!(老司机就是牛!!!)
- 说到这里,整个注入过程就完成了。具体怎么注入,一会我们从生成的源代码分析,这里先尝试着理解。为了生动易于理解,以上的分析不代表实际执行过程,但你这么理解是没有问题的。说到这里代码中各个注解的意思,应该已经理解了,不过这里还是提一下
- @Module:表明这个类是个Module类(Module仓库),会跟Component关联,这个类中可能有些提供方法可以向外提供一些类的实例
- @Provides:表明该方法是个提供方法,这个方法就是在Module中向外提供实例的方法(货架,提供的实例就是商品)
- @Component:表明这个接口是个Component(供货商),是连接Module(仓库) 和被注入类(商品),目标类(采购商)的桥梁,需要注入到哪个类,在inject方法中,目标类的实例作为参数传进来,这里注意下,我们这里的目标类是MainActivity,所以参数就是MainActivity的实例,但是我们不能用MainAcvity的父类接收,那样会报错的(MainActivity父亲的来都不行)。
4. Dagger2避免了反射对性能造成的影像,通过自动生成代码完成,注入。现在我们从它生成代码的角度去看看它到底是怎么完成注入的,自动生成的代码在\DaggerTest\app\build\generated\source\apt\debug\下面。下面看代码吧!!
- 我们以MainActivity中的调用顺序来看,代码的走向 **DaggerMainComponent.builder() **我们看这句代码做了些什么事
public static Builder builder() {
return new Builder();
}
这是个静态方法,new 了一个 Builder的实例返回,Builder为其内部类,构造方法中,什么也没有做。接着看MainActivity中下一步调用什么。
- 然后就是调用Bulider类的mainActivityModule(new MainActivityModule(this))方法,并且传入一个MainActivityModule的实例作为参数。而new一个MainActivityModule的实例需要传入MainActivity的实例,下面看这个方法做了什么.
public static final class Builder {
private MainActivityModule mainActivityModule;
private Builder() {}
public MainComponent build() {
if (mainActivityModule == null) {
throw new IllegalStateException(
MainActivityModule.class.getCanonicalName() + " must be set");
}
return new DaggerMainComponent(this);
}
public Builder mainActivityModule(MainActivityModule mainActivityModule) {
this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
return this;
}
}
这个方法,把传进来的MainActivityModule的实例被Builder这个类装进自己兜里了是不是?然后又返回了自己。
-
拿到返回的builder实例,MainActivity中继续调用Builder的build()方法,这个方法首先判断了下全局变量mainActivityModule,是否为空,为空就抛出异常。这个Builder,还真是贪婪,非要确认MainActiivtyModule的实例是不是已经装兜里了,然后就new个了DaggerMainComponent的实例返回,并把自己作为参数传了进去,注意:这时候的Buidler可不简单,是个小土豪,兜里装着MainActivityModule的实例,而MainAcvitivityModule的实例又有揣着 MainActivity的实例。
-
然后我们看下 DaggerMainComponent的new方法里都做了些什么,
public final class DaggerMainComponent implements MainComponent {
private Provider<MainActivity> provideMainActivityProvider;
private Provider<Presenter> presenterProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideMainActivityProvider =
MainActivityModule_ProvideMainActivityFactory.create(builder.mainActivityModule);
this.presenterProvider = Presenter_Factory.create(provideMainActivityProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(presenterProvider);
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private MainActivityModule mainActivityModule;
private Builder() {}
public MainComponent build() {
if (mainActivityModule == null) {
throw new IllegalStateException(
MainActivityModule.class.getCanonicalName() + " must be set");
}
return new DaggerMainComponent(this);
}
public Builder mainActivityModule(MainActivityModule mainActivityModule) {
this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
return this;
}
}
}
- 在DaggerMainComponent 的new方法里,它调用了initialize(builder),方法,并把Bulider实例传进去了,接着看initialize做了什么,
- 第一步它调用** MainActivityModule_ProvideMainActivityFactory.create(builder.mainActivityModule);**,这个类名很长,我们 就叫MF(Module工厂类),调用了MF 的creat方法,并把builder中的mainActivityModule传了进去作为参数(这下Bulider的财富被转移了,哈哈)MF的creat方法,new了一个MF返回,然后把mainActivityModule装自己兜里了,都贪财啊!然后DaggerMainComponent 用一个类接收了MF的实例给接收了,至于什么类,我们不用去关心,总之肯定是父类超类什么能接受的。下面是MF类的代码
public final class MainActivityModule_ProvideMainActivityFactory implements Factory<MainActivity> {
private final MainActivityModule module;
public MainActivityModule_ProvideMainActivityFactory(MainActivityModule module) {
assert module != null;
this.module = module;
}
@Override
public MainActivity get() {
return Preconditions.checkNotNull(
module.provideMainActivity(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<MainActivity> create(MainActivityModule module) {
return new MainActivityModule_ProvideMainActivityFactory(module);
}
}
- 第二步Presenter_Factory.create(provideMainActivityProvider);方法,Presenter_Factory.我们把这个类简称为PF(Presenter工厂类),调用PF的creat方法,并把MF的实例传进去。这时候的MF也是个富豪哦。 PF的creat方法,也没什么新意,依然是new一个PF实例返回,然后把MF实例装包包里,大鱼吃小鱼啊!DaggerMainComponent,又把PF实例收了。下面是PF的代码
public final class Presenter_Factory implements Factory<Presenter> {
private final Provider<MainActivity> mainActivityProvider;
public Presenter_Factory(Provider<MainActivity> mainActivityProvider) {
assert mainActivityProvider != null;
this.mainActivityProvider = mainActivityProvider;
}
@Override
public Presenter get() {
return new Presenter(mainActivityProvider.get());
}
public static Factory<Presenter> create(Provider<MainActivity> mainActivityProvider) {
return new Presenter_Factory(mainActivityProvider);
}
}
- 第三步 this.mainActivityMembersInjector = MainActivity_MembersInjector.create(presenterProvider); MainActivity_MembersInjector这个类我们简称为MI吧!这里依然是老套路,MI的creat方法,依然是返回MI的实例,然后把PF的实例装自己的兜里。DaggerMainComponent 依然是把MI的实例接收了。到目前为MI很富裕,它里面有PF的实例,而PF里有MF的实例,MF里有MainActivityModule的实例,而MainActivityModule中又有MainActivity的实例,大鱼吃小鱼下雨吃虾米的关系啊。下面是MI的代码
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<Presenter> mPresenterProvider;
public MainActivity_MembersInjector(Provider<Presenter> mPresenterProvider) {
assert mPresenterProvider != null;
this.mPresenterProvider = mPresenterProvider;
}
public static MembersInjector<MainActivity> create(Provider<Presenter> mPresenterProvider) {
return new MainActivity_MembersInjector(mPresenterProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mPresenter = mPresenterProvider.get();
}
public static void injectMPresenter(
MainActivity instance, Provider<Presenter> mPresenterProvider) {
instance.mPresenter = mPresenterProvider.get();
}
}
- 这时候我们已经拿到了DaggerMainComponent 的实例,再看下MainActivity中,又调用了DaggerMainComponent 的inject,方法,传入参数MainActivity的实例。这个方法又调用MI的injectMembers方法并把MainActivity的实例作为参数传进去了
- 在看Mi的injectMembers方法,这是个抽象方法,具体实现在MI里,那么我们到Mi里看呗。
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mPresenter = mPresenterProvider.get();
}
MI的injectMembers,方法把 MainActvity中的mPresenter 取出来了,mPresenter 是谁??,我们需要注入到MainActivity中的Presenter类的引用,只要它被实例化了,咱们工作基本就完成了,那么再看看等号的右边,mPresenterProvider.get(),mPresenterProvider何许人也?,他就是MI creat方法的时候传进来的PF实例,被MI包装了下,搞的差点不认识。(嘿嘿,整容了)。调用它的get方法,依然是个抽象方法,实现就在PF里,(仅仅是换个行头,所以该PF做的事还是PF做啊)
- 在看PF的get方法都干了些什么,
@Override
public Presenter get() {
return new Presenter(mainActivityProvider.get());
}
这里PF new了一个Presenter的实例并返回了,到这里,等号的左边(不要纠结于概念,你非要说在这里它不叫等号,那么我也只能无语)是Presenter的引用,右边是实例,mPresenter实例化完成,即注入完成。这里我们也看到,new Presenter的时候需要传入MainActivity实例作为参数,这里通过mainActivityProvider的get方法获取,mainActivityProvider是谁?不用多说了吧!就是经过整容的MF,可要认的出来才行。
- get方法,依然是抽象方法,具体实现在MF里。我们在看看MF的get方法
@Override
public MainActivity get() {
return Preconditions.checkNotNull(
module.provideMainActivity(), "Cannot return null from a non-@Nullable @Provides method");
}
调用了module的provideMainActivity方法,这 module是谁,不用再说了吧,就是MainActivityMoule的实例,它的provideMainActivity,方法返回什么,还是我们自己写的呢。就是返回MainActivity的实例。通过一系列的get方法,拿到MainActivity的实例,然后传到Presenter的new方法,这样Presenter就拿到了MainActivity的实例。到这里,所有的注入才算是真正完成。我们的最佳MVP也算是正在完成。
如果到这里你还不明白,不怕我们还有一招,看图 image
这里我就不做过多解释了,根据上面文字描述绘制的图谱,从new MainActivityModule开始,MainActivity的实例被包装到 Module里,然后整个Module 的实例又被包装到 Builder里,然后把Modle取出,再次包装到 MF里(Modle的工厂类)然后再 在包装到PF里,最后又把PF包装到MI里,然后再调用一系列的get方法取出this,完成注入。
网友评论