4.Dagger2

什么是Dagger2

1
2
Dagger 2是由Google开发的 依赖注入框架,它利用Java和Java注解处理器的强大功能,提供了一种优雅的方式来进行依赖注入。
Dagger 2基于一组注解和代码生成器,可以在编译时自动生成依赖注入的代码,从而提高性能和类型安全性。

dagger2 简单理解

1
2
3
4
5
1.一般我们使用一个实体类或者工具或者请求,比如在MainActivity中使用UerInfo.class,我们会在new Userinfo(),去使用
而dagger帮我们省略了这一步,dagger去管理new UserInfo(),我们直接在Activity中使用。
2.dagger 理解其实就是相当于买了快递后,快递送货流程
实现此流程需要四个注解 @Module @Component @Provides @Inject
如下图:

img

dagger2 的使用

1.在build.gradle中引入插件

1
2
3
4
// dagger2 的功能支持
implementation 'com.google.dagger:dagger:2.4'
// dagger2 自己的注解处理器
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

2.简单使用:

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
//1.HttpObject 对象-->快递
public class HttpObject {
private String HttpClient="client";
public String getHttpClient() {
return HttpClient;
}
public void setHttpClient(String httpClient) {
HttpClient = httpClient;
}
}
//2.HttpModule-->包裹
@Module// 包裹注解
public class HttpModule {
@Provides // 暴露出去注解
public HttpObject providerHttpObject(){
//........
return new HttpObject();
}
}
//3.Component 类似于快递员,拿到所有包裹->根据地址配给用户
//存放module的组件
@Component(modules = {HttpModule.class, DataModule.class})
public interface MyComponent {
//注入的位置就写在参数上 不能用多态
void injectMainActivity(Dagger2Activity mainActivity);
}
//4.用户使用-->接收快递
public class Dagger2Activity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
//rebuild项目后才有DaggerMyComponent文件,Dagger+自定义的Component名字
// 方式1: 注入
// DaggerMyComponent.create().injectMainActivity(this);
// 方式2:
DaggerMyComponent.builder().httpModule(new HttpModule()).build().injectMainActivity(this);
Log.e("tyl",httpObject.getHttpClient());
}
}

3.dagger2 单例使用

1
2
3
1.局域单例:存在于当前类中,只有一个实例,需要增加一个单例注解 @Singleton。
2.全局单例:存在于整个项目,只有一个实例,需要增加一个单例注解 @Singleton,全局单例需要配合Application使用,否则只能是
当前activity单例。

局域单例示例:(在moudle和Component类中添加@Singleton注解)

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
//1.moudle
@Module
public class HttpModule {
@Singleton
@Provides // 暴露出去注解
public HttpObject providerHttpObject(){
//........
return new HttpObject();
}
}
//2.Compinent类
@Singleton
@Component(modules = {HttpModule.class})
public interface MyComponent {
void injectMainActivity(Dagger2Activity dagger2Activity);
}
//3.使用示例:
public class Dagger2Activity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
HttpObject httpObject2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
//rebuild项目后才有DaggerMyComponent文件,Dagger+自定义的Component名字
// 方式1: 注入
// DaggerMyComponent.create().injectMainActivity(this);
// 方式2:
DaggerMyComponent.builder().httpModule(new HttpModule()).build().injectMainActivity(this);
Log.e("tyl",httpObject.hashCode()+"");
Log.e("tyl",httpObject2.hashCode()+"");
//得出结果值一样
}
}

全局单例示例:(在moudle和Component类中添加@Singleton注解)

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
43
44
45
46
47
48
49
50
51
52
53
//1.Component中添加次级要调用的类
@Singleton
@Component(modules = {HttpModule.class})
public interface MyComponent {
//多少个类就自定义多少个方法
void injectMainActivity(Dagger2Activity dagger2Activity);
void injectSecActivity(Dagger2Activity2 dagger2Activity2);
}
//2.application中注入
public class MyApplication extends Application {
private MyComponent myComponent;
private static MyApplication context;
@Override
public void onCreate() {
super.onCreate();
context = this;
myComponent = DaggerMyComponent.builder()
.httpModule(new HttpModule())
.build();
}
public static MyApplication getInstance() {
return context;
}
public MyComponent getMyComponent() {
return myComponent;
}
}
//3.主activity中执行调用
public class Dagger2Activity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
MyApplication.getInstance().getMyComponent().injectMainActivity(this);
Log.e("tyl",httpObject.hashCode()+"");
}
public void jump(View view) {
startActivity(new Intent(this,Dagger2Activity2.class));
}
}
//4.次activity中执行调用
public class Dagger2Activity2 extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.getInstance().getMyComponent().injectSecActivity(this);
Log.e("tyl",httpObject.hashCode()+"");
}
}

4.多个Component组合依赖

dagger2不能使用多个Component同时注入同一个类中 这种情况需要进行Component的组合;

先确定使用哪个 Component 作为主 Component,确定后,主 Component 仍然执行注入操作,而其他 Component 作为依赖项,不再执行注入,转而提供 Module 提供的对象。一般我们会选择 ApplicationComponent 作为主 Component。

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//1.新建一个对象DataObject
public class DataObject {
private String data="data";
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
//2.新建一个moudle
@Module
public class DataModule {
@Provides
public DataObject providerDatabaseObject(){
//........
return new DataObject();
}
}
//3.新建一个Component
@Component(modules = {DataModule.class})
public interface SecondComponent {
//使用依赖关系,就不再使用这种语法
//void injectMainActivity(Dagger2Activity dagger2Activity);
//直接提供object对象及自定义方法名
DataObject providerDatabaseObject();
}
//4.在ApplicationComponent 的 @Component 注解值中增加 dependencies,指定依赖的 Component:
@Singleton
@Component(modules = {HttpModule.class},dependencies = {SecondComponent.class})
public interface MyComponent {
void injectMainActivity(Dagger2Activity dagger2Activity);
void injectSecActivity(Dagger2Activity2 dagger2Activity2);
}
//5.application中新增指定的实现类
public class MyApplication extends Application {
private MyComponent myComponent;
private static MyApplication context;
@Override
public void onCreate() {
super.onCreate();
context = this;
myComponent = DaggerMyComponent.builder()
.httpModule(new HttpModule())
//指定 PresenterComponent 的实现类
.secondComponent(DaggerSecondComponent.create())
.build();
}
public static MyApplication getInstance() {
return context;
}
public MyComponent getMyComponent() {
return myComponent;
}
}
//6.使用
public class Dagger2Activity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
DataObject dataObject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
MyApplication.getInstance().getMyComponent().injectMainActivity(this);
Log.e("tyl",httpObject.hashCode()+"");
Log.e("tyl2",dataObject.getData()+"");
}
}
  1. @Scope

假如现在有个需求,想让 DataObject 也变成个单例对象,按照我们之前的做法,给 PresenterModule 中的 Provides 方法和 PresenterComponent 加上 @Singleton 之后,会发现编译报错了:

1
com.demo.dagger.component.ApplicationComponent also has @Singleton

它说 ApplicationComponent 中已经有 @Singleton 了。显然,Dagger2 要求 @Singleton 不能用在多个组件上。

1
2
3
4
5
6
使用 @Scope 的原则:

1.多个 Component 上面的 Scope 不能相同
2.没有 Scope 的 Component 不能依赖有 Scope 的组件
3.使用作用域注解的模块只能在带有相同作用域注解的组件中使用
4.使用构造方法注入(通过 @Inject)时,应在类中添加作用域注解;使用 Dagger 模块时,应在 @Provides 方法中添加作用域注解

@Scope 注解表示作用域,被其修饰的类或提供对象的方法会被做成单例,所以我们可以用 @Scope 自定义一个作用域注解:

1
2
3
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScope {}//自定义名字

实际上它和 @Singleton 一样只是名字不同:

1
2
3
4
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

以下示例编译报错,未查明原因

Component使用

1
2
3
4
5
6
7
@MyScope
@Component(modules = {DataObject.class})
public interface SecondComponent {
//使用依赖关系,就不再使用这种语法
// void inject(MainActivity activity);
DataObject providerDatabaseObject();
}

moudle使用

1
2
3
4
5
6
7
8
9
10
@Module
@MyScope
public class DataModule {
@MyScope
@Provides
public DataObject providerDatabaseObject(){
//........
return new DataObject();
}
}