Dagger2使用入门

Dagger2简介

Dagger2Dagger的升级版,是一个依赖注入框架,现在由Google接手维护。

Github:https://github.com/google/dagger

依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。

举个例子:我们在写面向对象程序时,往往会在一个类中引用另一个类,从而可以调用引用的类的方法完成某些功能,就像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的构造方法,不符合开闭原则

因此我们需要一种注入方式,将依赖注入到宿主类(或者叫目标类)中,从而解决上面所述的问题。依赖注入有以下几种方式:

通过接口注入

1
2
3
4
5
6
7
8
9
10
11
12
interface ClassBInterface {
void setB(ClassB b);
}

public class ClassA implements ClassBInterface {
ClassB classB;

@override
void setB(ClassB b) {
classB = b;
}
}

通过set方法注入

1
2
3
4
5
6
7
public class ClassA {
ClassB classB;

public void setClassB(ClassB b) {
classB = b;
}
}

通过构造方法注入

1
2
3
4
5
6
7
public class ClassA {
ClassB classB;

public void ClassA(ClassB b) {
classB = b;
}
}

通过Java注解

1
2
3
4
5
6
public class ClassA {
//此时并不会完成注入,还需要依赖注入框架的支持,如RoboGuice, Dagger2
@inject ClassB classB;

...
public ClassA() {}

在Dagger2中用的就是最后一种注入方式,通过注解的方式,将依赖注入到宿主类中。

Dagger2依赖注入

引入Dagger2

1
2
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依赖PresenterPresenter又需要依赖View接口,从而更新UI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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();
}
}

这样ActivityPresenter紧紧耦合在了一起,当需要改变Presenter的构造方式时,需要修改这里的代码。如果用依赖注入的话,是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();
}
}
1
2
3
public interface MainView {
void updateUI();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainPresenter {
//MainView是个接口
private MainView mView;

@Inject
MainPresenter(MainView view) {
mView = view;
}

public void loadData() {
//调用model层方法,加载数据
...
//回调方法成功时
mView.updateUI();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Module
public class MainModule {
private final MainView mView;

public MainModule(MainView view) {
mView = view;
}

@Provides
MainView provideMainView() {
return mView;
}
}
1
2
3
4
@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里完成注册:

1
2
3
4
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注解括号里的参数:

1
2
3
4
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}

所以Module要发挥作用,还是要依靠于Component类,一个Component类可以包含多个Module类,用来提供依赖。我们接着看下面这段代码:

1
2
3
4
5
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.homeModulw(new HomeModule(this))
.build()
.inject(this);

这里通过new MainModule(this)view传递到MainModule里,然后MainModule里的provideMainView()方法返回这个View,当去实例化MainPresenter时,发现构造函数有个参数,此时会在Module里查找提供这个依赖的方法,将该View传递进去,这样就完成了presenterView的注入。

Dagger2注入总结

我们来重新理一遍上面的注入过程,首先弄清楚以下几个概念:

  • @Inject 带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类
  • @Module 带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是提供所需的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖
  • @Component 用来将@Inject@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject

接着我们重新回顾一下上面的注入过程:首先MainActivity需要依赖MainPresenter,因此,我们在MainActivity中用@InjectMainPresenter进行标注,表明这是要注入的类。然后,我们对MainPresenter的构造函数也添加注解@Inject,此时构造函数里有一个参数MainView,因为MainPresenter需要依赖MainView,所以我们定义了一个类,叫做MainModule,提供一个方法provideMainView,用来提供这个依赖,这个MainView是通过MainModule的构造函数注入进来的,接着我们需要定义Component接口类,并将Module包含进来,即

1
2
3
4
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}

Dagger2注入原理

Dagger2与其他依赖注入框架不同,它是通过APT即注解处理器(Annotation Processing Tool)插件在编译阶段生成相应的注入代码,执行Build ProjectDagger2会在app/build/generated/ap_generated_sources/debug/out目录下生成对应的工厂类:

  • MainPresenter_Factory.java
  • MainModule_ProvideMainViewFactory.java
  • DaggerMainComponent.java
  • MainActivity_MembersInjector.java

构造方法 @Inject

MainPresenter_Factory是类MainPresenter的构造方法使用@Inject标注后构建生成的工厂类:

1
2
3
4
5
6
7
8
9
public class MainPresenter {
//MainView是个接口
private MainView mView;

@Inject
MainPresenter(MainView view) {
mView = view;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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是类MainModuleprovideMainView()方法使用@Provides标注后构建生成的工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Module
public class MainModule {
private final MainView mView;

public MainModule(MainView view) {
mView = view;
}

@Provides
MainView provideMainView() {
return mView;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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是类MainActivitymainPresenter成员变量使用@Inject标注后构建生成的辅助类,主要作用是初始化mainPresenter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
3
4
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);

DaggerMainComponent

1
2
3
4
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
1
2
3
4
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMainPresenter(instance, getMainPresenter());
return instance;
}

(2)构建MainPresenter,传入MainView

DaggerMainComponent

1
2
3
private MainPresenter getMainPresenter() {
return new MainPresenter(MainModule_ProvideMainViewFactory.provideMainView(mainModule));
}

(3)通过MainModule构建MainView

MainModule_ProvideMainViewFactory

1
2
3
public static MainView provideMainView(MainModule instance) {
return Preconditions.checkNotNull(instance.provideMainView(), "Cannot return null from a non-@Nullable @Provides method");
}

MainModule

1
2
3
4
@Provides
MainView provideMainView() {
return mView;
}

(4)初始化MainActivity中的mainPresenter

MainActivity_MembersInjector

1
2
3
4
@InjectedFieldSignature("me.yezhou.dagger2.MainActivity.mainPresenter")
public static void injectMainPresenter(MainActivity instance, MainPresenter mainPresenter) {
instance.mainPresenter = mainPresenter;
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2021 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :