Dagger2简介
Dagger2是Dagger的升级版,是一个依赖注入框架,现在由Google接手维护。
Github:https://github.com/google/dagger
依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。
举个例子:我们在写面向对象程序时,往往会在一个类中引用另一个类,从而可以调用引用的类的方法完成某些功能,就像下面这样:
public class ClassA {
...
ClassB b;
...
public ClassA() {
b = new ClassB();
}
public void do() {
...
b.doSomething();
...
}
}
这时就产生了依赖问题,ClassA依赖于ClassB,必须借助ClassB的方法,才能完成一些功能。这样看好像并没有什么问题,但是我们在ClassA的构造方法里面直接创建了ClassB的实例,问题就出现在这,在ClassA里直接创建ClassB实例,违背了单一职责原则,ClassB实例的创建不应由ClassA来完成;其次耦合度增加,扩展性差,如果我们想在实例化ClassB的时候传入参数,那么不得不改动ClassA的构造方法,不符合开闭原则。
因此我们需要一种注入方式,将依赖注入到宿主类(或者叫目标类)中,从而解决上面所述的问题。依赖注入有以下几种方式:
通过接口注入
interface ClassBInterface {
void setB(ClassB b);
}
public class ClassA implements ClassBInterface {
ClassB classB;
@override
void setB(ClassB b) {
classB = b;
}
}
通过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;
}
}
通过Java注解
public class ClassA {
//此时并不会完成注入,还需要依赖注入框架的支持,如RoboGuice, Dagger2
@inject ClassB classB;
...
public ClassA() {}
在Dagger2中用的就是最后一种注入方式,通过注解的方式,将依赖注入到宿主类中。

引入Dagger2
api 'com.google.dagger:dagger:2.28.3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.28.3'
使用Dagger2
例子基于mvp模式,在mvp中,最常见的一种依赖关系,就是Activity持有Presenter的引用,并在Activity中实例化这个Presenter,即Activity依赖Presenter,Presenter又需要依赖View接口,从而更新UI
public class MainActivity extends AppCompatActivity implements MainView {
private MainPresenter mainPresenter;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化presenter 将view传递给presenter
mainPresenter = new MainPresenter(this);
//调用Presenter方法加载数据
mainPresenter.loadData();
...
}
@Override
public void updateUI() {
Toast.makeText(this, "Dagger2", Toast.LENGTH_SHORT).show();
}
}
public class MainPresenter {
//MainView是个接口
private MainView mView;
MainPresenter(MainView view) {
mView = view;
}
public void loadData() {
//调用model层方法,加载数据
...
//回调方法成功时
mView.updateUI();
}
}
这样Activity与Presenter紧紧耦合在了一起,当需要改变Presenter的构造方式时,需要修改这里的代码。如果用依赖注入的话,是这样的:
public class MainActivity extends AppCompatActivity implements MainView {
@Inject
MainPresenter mainPresenter;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
//调用Presenter方法加载数据
mainPresenter.loadData();
...
}
@Override
public void updateUI() {
Toast.makeText(this, "Dagger2", Toast.LENGTH_SHORT).show();
}
}
public interface MainView {
void updateUI();
}
public class MainPresenter {
//MainView是个接口
private MainView mView;
@Inject
MainPresenter(MainView view) {
mView = view;
}
public void loadData() {
//调用model层方法,加载数据
...
//回调方法成功时
mView.updateUI();
}
}
@Module
public class MainModule {
private final MainView mView;
public MainModule(MainView view) {
mView = view;
}
@Provides
MainView provideMainView() {
return mView;
}
}
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
直接组合方式虽然简单,但是具有耦合性,为了解决这种耦合,可能就会多产生一些辅助类,让这种直接的依赖关系,变为间接,降低耦合。跟大多数设计模式一样,为了达到高内聚低耦合,往往会有很多接口与类,Daager2也是如此,虽然看似复杂了些,不过这在软件工程中是值得的。
先看MainActivity里的代码,之前是直接声明MainPresenter,现在在声明的基础上加了一个注解@Inject,表明MainPresenter是需要注入到MainActivity中,即MainActivity依赖于MainPresenter,这里要注意的是,使用@Inject时,不能用private修饰符修饰类的成员属性。
然后我们在MainPresenter的构造函数上同样加了@Inject注解。这样MainActivity里的mainPresenter与他的构造函数建立了某种联系。这种联系可以这样理解,当看到某个类被@Inject标记时,就会到它的构造方法中,如果这个构造方法也被@Inject标记的话,就会自动初始化这个类,从而完成依赖注入。
然后,他们之间并不会凭空建立起联系,肯定需要一个桥梁,将他们连接起来,也就是下面要介绍的Component。
Component是一个接口或者抽象类,用@Component注解标注(这里先不管括号里的modules),我们在这个接口中定义了一个inject()方法,参数是Mainactivity。然后rebuild一下项目,会生成一个以Dagger为前缀的Component类,这里是DaggerMainComponent,然后在MainActivity里完成注册:
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
此时Component就将@Inject注解的mainPresenter与其构造函数联系了起来。
完成Presenter的注入过程,发现还有一个MainModule类,MainModlue是一个注解类,用@Module注解标注,主要用来提供依赖。刚才通过@Inject就可以完成依赖,为什么这里还要用到Module类来提供依赖?之所以有Module类主要是为了提供那些没有构造函数的类的依赖,这些类无法用@Inject标注,比如第三方类库,系统类,以及上面示例的View接口。
我们在MainModule类里声明了MainView成员属性,在构造方法里将外界传进来的view赋值给mView,并通过一个@Provides标注的以provide开头的方法,将这个view返回,这个以provide开头的方法就是提供依赖的,我们可以创建多个方法来提供不同的依赖。那么这个类究竟是怎么作用的?可以想到上面提到的@Component注解括号里的参数:
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
所以Module要发挥作用,还是要依靠于Component类,一个Component类可以包含多个Module类,用来提供依赖。我们接着看下面这段代码:
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.homeModulw(new HomeModule(this))
.build()
.inject(this);
这里通过new MainModule(this)将view传递到MainModule里,然后MainModule里的provideMainView()方法返回这个View,当去实例化MainPresenter时,发现构造函数有个参数,此时会在Module里查找提供这个依赖的方法,将该View传递进去,这样就完成了presenter里View的注入。
Dagger2注入总结
我们来重新理一遍上面的注入过程,首先弄清楚以下几个概念:
@Inject带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类@Module带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是提供所需的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖@Component用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject
接着我们重新回顾一下上面的注入过程:首先MainActivity需要依赖MainPresenter,因此,我们在MainActivity中用@Inject对MainPresenter进行标注,表明这是要注入的类。然后,我们对MainPresenter的构造函数也添加注解@Inject,此时构造函数里有一个参数MainView,因为MainPresenter需要依赖MainView,所以我们定义了一个类,叫做MainModule,提供一个方法provideMainView,用来提供这个依赖,这个MainView是通过MainModule的构造函数注入进来的,接着我们需要定义Component接口类,并将Module包含进来,即
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
Dagger2注入原理
Dagger2与其他依赖注入框架不同,它是通过APT即注解处理器(Annotation Processing Tool)插件在编译阶段生成相应的注入代码,执行Build Project,Dagger2会在app/build/generated/ap_generated_sources/debug/out目录下生成对应的工厂类:
MainPresenter_Factory.javaMainModule_ProvideMainViewFactory.javaDaggerMainComponent.javaMainActivity_MembersInjector.java
构造方法 @Inject
类MainPresenter_Factory是类MainPresenter的构造方法使用@Inject标注后构建生成的工厂类:
public class MainPresenter {
//MainView是个接口
private MainView mView;
@Inject
MainPresenter(MainView view) {
mView = view;
}
}
public final class MainPresenter_Factory implements Factory<MainPresenter> {
private final Provider<MainView> viewProvider;
public MainPresenter_Factory(Provider<MainView> viewProvider) {
this.viewProvider = viewProvider;
}
@Override
public MainPresenter get() {
return newInstance(viewProvider.get());
}
public static MainPresenter_Factory create(Provider<MainView> viewProvider) {
return new MainPresenter_Factory(viewProvider);
}
public static MainPresenter newInstance(MainView view) {
return new MainPresenter(view);
}
}
@Provides
类MainModule_ProvideMainViewFactory是类MainModule的provideMainView()方法使用@Provides标注后构建生成的工厂类:
@Module
public class MainModule {
private final MainView mView;
public MainModule(MainView view) {
mView = view;
}
@Provides
MainView provideMainView() {
return mView;
}
}
public final class MainModule_ProvideMainViewFactory implements Factory<MainView> {
private final MainModule module;
public MainModule_ProvideMainViewFactory(MainModule module) {
this.module = module;
}
@Override
public MainView get() {
return provideMainView(module);
}
public static MainModule_ProvideMainViewFactory create(MainModule module) {
return new MainModule_ProvideMainViewFactory(module);
}
public static MainView provideMainView(MainModule instance) {
return Preconditions.checkNotNull(instance.provideMainView(), "Cannot return null from a non-@Nullable @Provides method");
}
}
这里不难发现一种对应关系,在MainModule中定义的@Provides修饰的方法都会对应的生成一个对应工厂类,这里是MainModule_ProvideMainViewFactory
@Component
类DaggerMainComponent是类MainComponent使用@Component标注后构建生成的辅助类,@Component是连接@Module和@Inject的桥梁,主要作用是执行inject方法,为MainPresenter构造方法赋值参数MainView
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
public final class DaggerMainComponent implements MainComponent {
private final MainModule mainModule;
private DaggerMainComponent(MainModule mainModuleParam) {
this.mainModule = mainModuleParam;
}
public static Builder builder() {
return new Builder();
}
private MainPresenter getMainPresenter() {
return new MainPresenter(MainModule_ProvideMainViewFactory.provideMainView(mainModule));
}
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMainPresenter(instance, getMainPresenter());
return instance;
}
public static final class Builder {
private MainModule mainModule;
private Builder() {
}
public Builder mainModule(MainModule mainModule) {
this.mainModule = Preconditions.checkNotNull(mainModule);
return this;
}
public MainComponent build() {
Preconditions.checkBuilderRequirement(mainModule, MainModule.class);
return new DaggerMainComponent(mainModule);
}
}
}
引用注入 @Inject
类MainActivity_MembersInjector是类MainActivity的mainPresenter成员变量使用@Inject标注后构建生成的辅助类,主要作用是初始化mainPresenter
public class MainActivity extends AppCompatActivity implements MainView {
@Inject
MainPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
//调用Presenter方法加载数据
mainPresenter.loadData();
}
@Override
public void updateUI() {
Toast.makeText(this, "AppBlog.CN", Toast.LENGTH_SHORT).show();
}
}
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<MainPresenter> mainPresenterProvider;
public MainActivity_MembersInjector(Provider<MainPresenter> mainPresenterProvider) {
this.mainPresenterProvider = mainPresenterProvider;
}
public static MembersInjector<MainActivity> create(
Provider<MainPresenter> mainPresenterProvider) {
return new MainActivity_MembersInjector(mainPresenterProvider);
}
@Override
public void injectMembers(MainActivity instance) {
injectMainPresenter(instance, mainPresenterProvider.get());
}
@InjectedFieldSignature("me.yezhou.dagger2.MainActivity.mainPresenter")
public static void injectMainPresenter(MainActivity instance, MainPresenter mainPresenter) {
instance.mainPresenter = mainPresenter;
}
}
调用流程
(1)inject调用
MainActivity
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
DaggerMainComponent
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMainPresenter(instance, getMainPresenter());
return instance;
}
(2)构建MainPresenter,传入MainView
DaggerMainComponent
private MainPresenter getMainPresenter() {
return new MainPresenter(MainModule_ProvideMainViewFactory.provideMainView(mainModule));
}
(3)通过MainModule构建MainView
MainModule_ProvideMainViewFactory
public static MainView provideMainView(MainModule instance) {
return Preconditions.checkNotNull(instance.provideMainView(), "Cannot return null from a non-@Nullable @Provides method");
}
MainModule
@Provides
MainView provideMainView() {
return mView;
}
(4)初始化MainActivity中的mainPresenter
MainActivity_MembersInjector
@InjectedFieldSignature("me.yezhou.dagger2.MainActivity.mainPresenter")
public static void injectMainPresenter(MainActivity instance, MainPresenter mainPresenter) {
instance.mainPresenter = mainPresenter;
}




