Dagger是一个完全静态的、编译时的依赖注入框架,适用于java、Kotlin语言,主要用在Android开发中。早期要Square创建,现在由Google进行维护。
Dagger相比较其它依赖注入框架最大优势是没有采用反射技术,使用APT技术。
引入Dagger
在Moudle的build中引入
implementation 'com.google.dagger:dagger-android:2.41'
implementation 'com.google.dagger:dagger-android-support:2.41' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.41'
annotationProcessor 'com.google.dagger:dagger-compiler:2.41'
注解的初步使用
四个基础的注解:
- @Inject 主要有两个作用,一个是使用构造函数上,通过标记构造函数唐Dagger2来使用(Dagger2通过这个标记可以在需要这个类实例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖,另外一个作用就是标记在需要依赖的变量让Dagger2为其提供依赖。
@Inject还能使用在方法上,用来set变量 - @Component 一般用于标注接口,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需要依赖方之间的桥梁,把相关依赖注入其中。Component标注的接口在编译时会生成该接口的实现类(例如MainActivityComponent标注的接口会生成接口类DaggerMainActivityComponent)。
第一种使用方法:
1.生成@Inject标注的构造方法
2.生成@Component标注的中间接口
3.@Inject标注变量
4。通过DaggerxxxComponent实现注入
public class Car {
@Inject
public Car() {
}
public String show(){
return getClass().getSimpleName();
}
}
接下来需要创建一个用@Component标注的接口,这个接口是一个注入器,用来将对象实例注入到调用方。
@Component
public interface MainComponent {
void inject(MainActivity mainActivity);
}
完成后可能需要reBuild项目生成DaggerMainComponent类。
public class MainActivity extends AppCompatActivity {
//定义需要被注入的实例
@Inject
Car mCar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实现注入
DaggerMainComponent.create().inject(this);
Toast.makeText(this,"this is " + mCar.show(),Toast.LENGTH_LONG).show();
}
}
带参构造方法或者第三方对象注入
在开发中经常使用到第三方或者有参数的构造方法,这时候我们应该如何进行标注?这时候需要使用@Module和@Provide
- @Provide用来标注一个方法,该方法可以需要提供依赖时被调用,从而把预先提供好的对象当做依赖标注了@Injection的变量赋值。Provide主要用于标注Module里的方法。
1.创建两个类
public class Gear {
public Gear() {
}
@NonNull
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class Engine {
public Engine(Gear gear) {
gear.toString();
}
}
Engine构造方法中有使用Gear的对象
创建Module类
@Module
public class MainActivityModule {
@Provides
public Engine provideEngine(){
return new Engine(new Gear());
}
}
这里使用了@Module标注了类用@Provides标注方法
@Component(modules = {MainActivityModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
modules类
//modules 中可以有多个Module类,通过","隔开
@Component(modules = {MainActivityModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
实现注入
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
//定义需要被注入的实例
@Inject
Car mCar;
@Inject
Engine mEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实现注入
DaggerMainComponent.create().inject(this);
//Toast.makeText(this,"this is " + mCar.show(),Toast.LENGTH_LONG).show();
Toast.makeText(this,"this is " + mEngine.toString(),Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate: " + mCar.show() + " Engine " + mEngine.toString());
}
}
限定符
在面向接口编程中,经常需要使用一个接口,多个实现类的方式进行操作,那么应该如何进行这种类型的初始化?这里需要使用到@Qualifier或者@name注解,同时这也是当对象有多个构造函数时的解决方法。
- @Qualifier限定符,可以用来给注解做注解
- @Named是被@Qualifier注解的,可以省略手动创建注解类,主要用来注解方法和对象
操作需要两步:
1.创建@Qualifier注解过的注解
2.给Provider方法加上@Qualifier注解
示例:
创建一个接口
public interface Mechanical {
}
创建注解
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifierCar {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifierEngine {
}
修改Car和Engine
public class Car implements Mechanical{
@Inject
public Car() {
}
@NonNull
@Override
public String toString() {
return getClass().getSimpleName();
}
}
public class Engine implements Mechanical{
@Inject
public Engine(Gear gear) {
gear.toString();
}
}
修改Module类
@Module
public class MainActivityModule {
@QualifierEngine
@Provides
public Mechanical provideEngine(){
return new Engine(new Gear());
}
@QualifierCar
@Provides
public Mechanical provideCar(){
return new Car();
}
}
//modules 中可以有多个Module类,通过","隔开
@Component(modules = {MainActivityModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
使用
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
//定义需要被注入的实例
@QualifierCar
@Inject
Mechanical mCar;
@QualifierEngine
@Inject
Mechanical mEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实现注入
DaggerMainComponent.create().inject(this);
//Toast.makeText(this,"this is " + mCar.show(),Toast.LENGTH_LONG).show();
Toast.makeText(this,"this is " + mEngine.toString(),Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate: " + mCar.toString() + " Engine " + mEngine.toString());
}
}
@Named的使用方法为:
1.使用@Named标记Module中生成类实例的方法
2.使用@Named标注目标类中相应类实例
@Module
public class MainActivityModule {
@Named("Engine")
@Provides
public Mechanical provideEngine(){
return new Engine(new Gear());
}
@Named("Car")
@Provides
public Mechanical provideCar(){
return new Car();
}
}
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
//定义需要被注入的实例
@Named("Car")
@Inject
Mechanical mCar;
@Named("Engine")
@Inject
Mechanical mEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实现注入
DaggerMainComponent.create().inject(this);
//Toast.makeText(this,"this is " + mCar.show(),Toast.LENGTH_LONG).show();
Toast.makeText(this,"this is " + mEngine.toString(),Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate: " + mCar.toString() + " Engine " + mEngine.toString());
}
}
@Named相当于把@Qualifier封装了一下,操作起来更简单