Dagger2 简介
Dagger2 使用的是APT技术,
APT全称Annotation Processing Tool,即注解处理器,也就是在编译时扫描和处理使用的那些注解,
根据不同的注解生成对应在类文件,从而帮忙我们自动生成对应的逻辑
使用APT可以在编译时处理注解,有如下效果:
①可以达到减少重复代码手工编写的效果。
②获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。
APT并不是对源文件进行修改,只能获取注解信息和被注解对象的信息,然后做一些自定义的处理。
而在 Dagger2 中 可以让我们在一个类中, 直接通过注解,在编译的时候,自动帮我们new 出一个对象,所以我们只需要这么写,他在运行的时候就不是空的。
@Inject
Fruit fruit;
使用配置
使用 Dagger2 需要先引入第三方。
// dagger2 的功能支持
implementation 'com.google.dagger:dagger:2.4'
// dagger2 自己的注解处理器
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
基本使用
这里面需要先引入几个成员。
对象,包裹@Module 快递员@dagger.Component
其实很简单的逻辑,就是,对象放在对应的包裹里面。而一个快递员可以存放多个包裹,包裹里面可以存放对应的对象。并且快递员需要知道是谁需要拿包裹对象。
那么对应的类实现就是:
//对象
public class Fruit {
}
@Module // 加上 @Module注解 证明这个 FruitModule 是包裹 Module
public class FruitModule {
@Provides //加上注解 @Provides 把对象提供给包裹
public Fruit getFruit(){
return new Fruit();
}
}
//注解 Component 代表这个类是 Component 快递员. 他里面存放各种各样的包裹,包裹里面有对应的对象
@dagger.Component(modules = {FruitModule.class,StudentModule.class})
public interface ComponentDiy {
//需要提供一个方法。现在是 MainActivity2需要拿快递员的 包裹,所以需要把 MainActivity2 这个对象传进来给 快递员,快递员才知道包裹要给谁。
void needByInject(MainActivity2 mainActivity2);
// 如果说MainActivity1 这个类也需要从快递员拿包裹,那么你也需要再提供一个对应的方法,参数是MainActivity1 这个类,然后再去编译生成对应的代码
void needByInject(MainActivity1 mainActivity1);
}
当你定义一个接口快递员 ComponentDiy的时候,这个时候还没有 DaggerComponentDiy这个类。
这个时候你需要执行编译,在编译期就会 自动帮你生产一个叫做 DaggerComponentDiy 这个类。然后你在 MainActivity2 中利用这个类DaggerComponentDiy 去把 MainActivity2 给传给 DaggerComponentDiy 。 这样,后续,你在 MainActivity2 就可以直接通过
@Inject
Fruit fruit;
去自动帮你创建一个对象了。
public class MainActivity2 extends AppCompatActivity{
@Inject
Fruit fruit;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//方式一,代表把 MainActivity2 给到快递员 ComponentDiy 。MainActivity2 需要拿快递员里面的包裹
DaggerComponentDiy.create().injectMainAct(this);
//还有一种方式。其实就是创建一个快递员,然后设置对应的包裹,并且把当前 MainActivity2 给提供进去
DaggerComponentDiy.builder()
.fruitModule(new FruitModule ()) //多个包裹就设置多个
.studentModule(new StudentModule ())//多个包裹就设置多个
.build()
.injectMainAct(this);
}
}
注意的是 在一个类中,
public class MainActivity2 extends AppCompatActivity{
@Inject
Fruit fruit1;
@Inject
Fruit fruit2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerComponentDiy.create().injectMainAct(this);
}
}
fruit1 和fruit2 他们是不同的对象,相当于
fruit1 = new Fruit();
c= new Fruit();
怎么会是相同的对象呢。
如果说想要做到 让他们是同一个对象,其实也就是做单例,这里说的是局部单例,也就是只在同一个类,比如MainActivity2 中,让 fruit1 和 fruit2 都是同一个对象,而不是两个。
那么要做的就是在 提供对象上,对象包裹上,快递员上 都加上 @Singleton 单例的注解 也就是
//包裹加上注解
@Singleton
@Module // 加上 @Module注解 证明这个 FruitModule 是包裹 Module
public class FruitModule {
//提供对象加上注解
@Singleton
@Provides //加上注解 @Provides 把对象提供给包裹
public Fruit getFruit(){
return new Fruit();
}
}
@Singleton //快递员加上注解
//注解 Component 代表这个类是 Component 快递员. 他里面存放各种各样的包裹,包裹里面有对应的对象
@dagger.Component(modules = {FruitModule.class,StudentModule.class})
public interface ComponentDiy {
//需要提供一个方法。现在是 MainActivity2需要拿快递员的 包裹,所以需要把 MainActivity2 这个对象传进来给 快递员,快递员才知道包裹要给谁
void needByInject(MainActivity2 mainActivity2);
}
那么 MainActivity2 中,让 fruit1 和 fruit2 都是同一个对象。
那么如果想实现全局单例呢,也就是在 MainActivity2 中我加了 fruit1 。并且在 MainActivity1 也我也加了 fruit1 。并且我希望他们的fruit1 是一个对象,而不是两个。
那么方法就是在局部单例加 @Singleton 注解标签外,
不再是在单个 MainActivity2 去
DaggerComponentDiy.create().injectMainAct(this);
而是在先自定义 Application
public class MyApplication extends Application {
ComponentDiy componentDiy;
if(componentDiy ==null){
componentDiy = DaggerComponentDiy.builder()
.fruitModule(new FruitModule ()) //多个包裹就设置多个
.studentModule(new StudentModule ())//多个包裹就设置多个
.build()
}
}
然后再需要的Activity 如这里的 MainActivity2 MainActivity1 下加上
((MyApplication)getApplication()).componentDiy.injectMainAct(this);
那么 MainActivity2 MainActivity1的fruit 就是一个对象了。
其实全局单例就是在独一的application上,只创建一个快递员 componentDiy。
而局部单例是在每个activity都创建了一个快递员 componentDiy。