Dagger2使用详解

Dagger2简介

Dagger2是Dagger的升级版,是一个依赖注入框架,第一代由大名鼎鼎的Square公司共享出来,第二代则是由谷歌接手后推出的,现在由Google接手维护。

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

依赖注入

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

举个栗子:

1
2
3
4
5
6
7
public class ClassA {
private ClassB b

public ClassA(ClassB b) {
this.b = b;
}
}

这里ClassA的构造函数里传了一个参数ClassB,随着后续业务增加也许又需要传入ClassCClassD。试想一下如果一个工程中有5个文件使用了ClassA那是不是要改5个文件?

这既不符合开闭原则,也不符合单一职责原则,这个时候大杀器Dagger2就该出场了:

1
2
3
4
5
6
7
public class ClassA {
@inject
private ClassB b;

public ClassA() {
}
}

通过注解的方式将ClassB b注入到ClassA中,可以灵活配置ClassA的属性而不影响其他文件对ClassA的使用。

简单的说,就是一个工厂模式,由Dagger负责创建工厂,帮忙生产instance。遵从Java规范JSR 330,可以使用这些注解。现在不研究Dagger2是如何根据注解去生成工厂的,理解为什么可以实现DI(Dependency Injection),如何创建IoC(Inverse of Control)容器。

Dagger2依赖注入

Dagger2使用

在实际项目中Dagger2一般和MVP模式配合使用

引入Dagger2

1
2
api 'com.google.dagger:dagger:2.28.3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.28.3'

定义IView

1
2
3
4
//IView类
public interface ICommonView {
Context getContext();
}

定义Module

创建一个类CommonModule

1
2
3
4
5
6
7
8
9
10
11
12
13
@Module
public class CommonModule {
private ICommonView iView;

public CommonModule(ICommonView iView) {
this.iView = iView;
}

@Provides
public ICommonView provideIcommonView() {
return this.iView;
}
}

定义Component

创建一个接口CommonComponent

1
2
3
4
@Component (modules = CommonModule.class)
public interface CommonComponent {
void inject(LoginActivity activity);
}

定义Presenter

build一下项目,然后在LoginPresenter里使用@Inject@Inject来自javax包,不是Dagger2自定义的)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LoginPresenter {
ICommonView iView;

@Inject
public LoginPresenter(ICommonView iView) {
this.iView = iView;
}

public void login(User user) {
Context mContext = iView.getContext();
Toast.makeText(mContext, "login......", Toast.LENGTH_SHORT).show();
}
}

使用CommonComponent接口

LoginActivity中使用CommonComponent接口

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
public class LoginActivity extends AppCompatActivity implements ICommonView {
@BindView(R.id.btn_login)
Button btn;
@Inject
LoginPresenter presenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
DaggerCommonCompnent
.builder()
.commonModule(new CommonModule(this))
.build()
.inject(this);
}

@OnClick(R.id.btn_login)
void login() {
presenter.login(new User());
}

@Override
protected void onDestroy() {
super.onDestroy();
}

@Override
public Context getContext() {
return this;
}
}

解耦

有没有注意到loginPresenter并没有初始化?这个简单Demo要展示的重点就是loginPresenterLoinActivity彻底解藕,后续无论怎样修改loginPresenter的构造方法都不需要改动LoinActivity的代码。如果loginPresenter构造函数增加参数要改谁的代码呢?当然是CommonModudle了,其实也很简单,例如增加了一个新参数ImyView就在CommonModudle.java中新增一个方法

1
2
3
4
@Provides
public ImyView provideMyView() {
return myView; // myView是ImyView的实例
}

注意别漏了@Provides,它是Dagger2自定义的注解,也是通过它Dagger2才能正常把新增的参数传入loginPresenter构造器。

命名规约

  • @Provides方法用provide前缀命名
  • @ModuleModule后缀命名
  • @ComponentComponent作为后缀

Dagger2总结

Dagger2是通过依赖注入完成类的初始化,这个过程需要三部分:

  • 依赖提供方(生产者)
  • 依赖注入容器(桥梁)
  • 依赖需求方(消费者)

Dagger2是怎么选择依赖提供的呢,规则是这样的:

步骤1:查找Module中是否存在创建该类的方法
步骤2:若存在创建类方法,查看该方法是否存在参数
步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数
步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束

Powered by AppBlog.CN     浙ICP备14037229号

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

访客数 : | 访问量 :