Dagger2是正方形公司推出的一款依赖注入的框架,第二代由谷歌接手,在Android届可是大名鼎鼎的难学,我也是反复看了一遍又一遍才稍微有点头绪,本文就是Dagger2的使用指北,包括后面如何集成到项目中,也尽量写下来。
1.引入
implementation 'com.google.dagger:dagger:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
2.Dagger2的作用是什么呢?
我们来看这样一个例子,假如此时有一个Apple类,要在MainActivity中使用该类,传统的方法,是在MainActivity类中new出这个对象,如下:
public class MainActivity extends AppCompatActivity {
//使用
Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apple = new Apple(20);
Log.i("我是一个苹果","");
}
}
但是使用Dagger2,就不再需要new出Apple类,直接注入即可。如下:
public class MainActivity extends AppCompatActivity {
//使用
@Inject
Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入
DaggerGangJingComponent.builder().appleModule(new AppleModule(90))
.build().inject(this);
Log.i("我是一个苹果","");
}
}
那么我们现在就是需要在项目中使用这个Apple类,怎么来使用Dagger2来创建呢?有哪些创建方式呢?后文会详细解释清楚。
1.最简单不带Module的inject方式
由我们自己定义的类,我们可以自由修改的前提下使用这种方式,分为两种:带参和不带参。
构造函数不带参的类:
- 由类提供:
//第一,将我们需要注入的对象的类的构造参数使用@Inject标注,告诉dagger2它可以实例化这个类;
public class Apple {
@Inject
public Apple() {
}
}
2.由component连接
//第二,编写Component接口使用@Component进行标注,里面的void inject()的参数表示要将依赖注入到的目标位置;
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
3.使用Apple
//
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第三,使用android studio的Build菜单编译一下项目,使它自动生成我们编写的Component所对应的类,生成的类的名字的格式为 "Dagger+我们所定义的Component的名字";
//第四,在需要注入的类中使用@Inject标注要注入的变量;然后调用自动生成的Component类的方法create()或builder().build(),然后inject到当前类;在这之后就可以使用这个@Inject标注的变量了。
DaggerAppleComponent.create().inject(this);
Log.i("苹果",apple+"");
}
}
构造函数带参数的类,参数为引用类型
如果参数是基本类型呢?
- 假如Apple中带有一个Kinfe类的参数如下:
public class Apple {
Knife knife;
//Apple的构造方法使用@Inject标注,告诉Dagger2可以实例化这个类
@Inject
public Apple(Knife knife) {
this.knife = knife;
}
}
2.参数Knife的构造方法也需要提供注入,由@Inject标记,告诉Dagger2可以实例化这个类。
public class Knife {
@Inject
public Knife() {
}
}
3.使用component连接二者:类和要注入该类的目标位置。inject的参数就是要把该类注入到的目标位置。
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
4.Bulid一下项目,生成一个DaggerAppleComponent,通过该类使用注入的对象。
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入Apple
DaggerAppleComponent.create().inject(this);
//使用Apple
Log.i("苹果",apple+","+apple.knife);
}
2.带Module的Inject方式
在不能更改构造函数的情况下(比如引入第三方类OkHttpClient等),我们无法在构造函数上添加@Inject标记,就只能使用Module来实现类的提供。
构造方法不带参数
1.假如我们的Apple类是由第三方提供的,我们不可以更改其代码。
public class Apple {
Knife knife;
public Apple() {
}
public Knife getKnife() {
return knife;
}
public void setKnife(Knife knife) {
this.knife = knife;
}
}
2.编写Module类,并且使用@Module标注,在该类中提供我们需要inject的对象,提供该对象的方法使用@Provides标注
@Module
public class AppleModule {
@Provides
public Apple providesApple(){
return new Apple();
}
}
3.在component接口中,使用modules = xxxModule.class链接上一步编写的Module类。
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
}
4.依然是在目标位置注入该对象,并使用
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.create().inject(this);
Log.i("苹果",apple+"");
}
}
构造函数带参数
1.编写Module类,使用@Module标记,并且在Module的构造方法中传入参数,参数和对象一样,都需要写个方法提供出来。
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
public Apple providesApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
2.component接口写法同上
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
}
3.build一下,生成DaggerXXXModule类,使用该类的build方法并传入参数来注入对象。
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("蓝色的苹果"))
.build().inject(this);
Log.i("苹果",apple+"");
}
}
@Qualifier 自定义注解
现在有这样的情况,如果一个类,有两个构造方法,一个带参,一个不带参,如果要同时使用带参和不带参的对象,那么怎么来区分呢?
1. 使用@Named注解进行标记。
使用该类型注解(@Named或者@Qualifier),不能直接在构造函数上标记,否则会报错误:
@Qualifier annotations are not allowed on @Inject constructors.
在Module类中,使用@Named注解标记:
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
@Named("normal")
public Apple providesApple(){
return new Apple();
}
@Provides
@Named("named")
public Apple providesNamedApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
2.使用时需要使用@Named进行区分。
public class MainActivity extends AppCompatActivity {
@Inject
@Named("normal")
public Apple apple;
@Inject
@Named("named")
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("红色")).build()
.inject(this);
Log.i("苹果",apple+"");
Log.i("苹果1",apple1+""+apple1.name);
}
}
3.其它创建Component接口的代码均相同。
2.使用@Qualifier自定义注解
1.创建一个注解类 命名为Type,并用@Qualifier注解标记,需要指明是运行时注解。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
String value() default "";
}
2.把上一步中的Named全部换成自己定义的Type即可。
在Module中:
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
@Type("normal")
public Apple providesApple(){
return new Apple();
}
@Provides
@Type("named")
public Apple providesNamedApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
使用时:
public class MainActivity extends AppCompatActivity {
@Inject
@Type("normal")
public Apple apple;
@Inject
@Type("named")
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("红色")).build()
.inject(this);
Log.i("苹果",apple+"");
Log.i("苹果1",apple1+""+apple1.name);
}
}
Singleton 单例
怎样使用Dagger2创建单例对象呢?
无Module方式
1.在对象类上使用@Singleton标记
@Singleton
public class Apple {
@Inject
public Apple() {
}
}
2.使用@Singleton标记component接口
@Singleton
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
3.注入并使用Apple对象
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Inject
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.create().inject(this);
Log.i("苹果",apple+"");
Log.i("苹果1",apple1+"");
}
}
打印结果如下:
有Module方式
出现Module类的初衷是对象类不可更改,因此,有Module类时,不需要对对象类进行任何的更改,使用单例也只需要在Module类中进行更改即可。
1.Module类中提供对象的方法上,使用@Singleton标记。
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Singleton
@Provides
public Apple providesApple(){
return new Apple();
}
@Provides
public String providesName(){
return name;
}
}
2.其他代码相同:包括使用@Singleton标记component接口,注入并使用对象。
@Scope 作用域
在作用域内单例。比如有三个Activity,只在前两个Activity中实现单例。
1.创建自定义注解,使用@Scope注解标记,并标明是运行时注解。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
2.Module 和 component都是用自定义的@PerActivity进行标记。
Module:
@Module
public class AppleModule {
@Provides
@PerActivity
public Apple providesApple(){
return new Apple();
}
}
Component:
@PerActivity
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
void inject(Main2Activity activity);
}
3.光使用注解划定作用域还是不够的,还需要创建一个Application,在其中获取获取AppleComponent对象。
public class AppleApplication extends Application {
private AppleComponent appleComponent;
@Override
public void onCreate() {
super.onCreate();
// 获取AppleComponent对象
appleComponent = DaggerAppleComponent.builder().appleModule(new AppleModule())
.build();
}
//提供外界获取AppleComponent的方法
public AppleComponent getAppleComponent() {
return appleComponent;
}
}
4.在需要使用单例Apple的位置获取AppleComponent对象,并且注入
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((AppleApplication)getApplication()).getAppleComponent().inject(this);
Log.i("Main 苹果", "onCreate: "+apple);
findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this,Main2Activity.class));
}
});
}
}
Main2Activity.java
public class Main2Activity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
((AppleApplication)getApplication()).getAppleComponent().inject(this);
Log.i("Main2 苹果",apple+"");
findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(Main2Activity.this,Main3Activity.class));
}
});
}
}
打印出的结果如下:
Main 苹果: onCreate: com.kimliu.daggerdemo3.Apple@5ef1d24
Main2 苹果: com.kimliu.daggerdemo3.Apple@5ef1d24
可以看到,两个对象的地址相同。
5.不使用单例的目标位置(Main3Activity),需要使用Apple,重新编写Module,Component注入使用即可。
Module:
@Module
public class Main3Module {
@Provides
public Apple providesApple(){
return new Apple();
}
}
Component:
@Component(modules = Main3Module.class)
public interface Main3Component {
void inject(Main3Activity activity);
}
//使用:
public class Main3Activity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
DaggerMain3Component.create().inject(this);
Log.i("Main3Activity 苹果", "onCreate: "+apple);
}
}
本文参考:https://www.jianshu.com/p/22c397354997/
https://www.jianshu.com/p/ea4b89352e9a 感谢