Dagger系列(二)常用注解的使用:
Dagger2起源于Dagger,是一款基于Java注解来实现的完全在编译阶段完成依赖注入的开源库,主要用于模块间解耦、提高代码的健壮性和可维护性。Dagger2在编译阶段通过apt利用Java注解自动生成Java代码,然后结合手写的代码来自动帮我们完成依赖注入的工作。
Dagger2注解 :
我们在使用dagger2 的时候经常用到一些注解:
@Inject
@Inject有两个作用,一是用来标记需要依赖的变量,以此告诉Dagger2为它提供依赖;二是用来标记构造函数,Dagger2通过@Inject注解可以在需要这个类实例的时候来找到这个构造函数并把相关实例构造出来,以此来为被@Inject标记了的变量提供依赖;
@Module
@Module用于标注提供依赖的类。你可能会有点困惑,上面不是提到用@Inject标记构造函数就可以提供依赖了么,为什么还需要@Module?很多时候我们需要提供依赖的构造函数是第三方库的,我们没法给它加上@Inject注解,又比如说提供以来的构造函数是带参数的,如果我们之所简单的使用@Inject标记它,那么他的参数又怎么来呢?@Module正是帮我们解决这些问题的。
@Provides
@Provides用于标注Module所标注的类中的方法,该方法在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Inject的变量赋值;
@Component
@Component用于标注接口,是依赖需求方和依赖提供方之间的桥梁。被Component标注的接口在编译时会生成该接口的实现类(如果@Component标注的接口为CarComponent,则编译期生成的实现类为DaggerCarComponent),我们通过调用这个实现类的方法完成注入;
@Qulifier
@Qulifier用于自定义注解,也就是说@Qulifier就如同Java提供的几种基本元注解一样用来标记注解类。我们在使用@Module来标注提供依赖的方法时,方法名我们是可以随便定义的(虽然我们定义方法名一般以provide开头,但这并不是强制的,只是为了增加可读性而已)。那么Dagger2怎么知道这个方法是为谁提供依赖呢?答案就是返回值的类型,Dagger2根据返回值的类型来决定为哪个被@Inject标记了的变量赋值。但是问题来了,一旦有多个一样的返回类型Dagger2就懵逼了。@Qulifier的存在正式为了解决这个问题,我们使用@Qulifier来定义自己的注解,然后通过自定义的注解去标注提供依赖的方法和依赖需求方(也就是被@Inject标注的变量),这样Dagger2就知道为谁提供依赖了。----一个更为精简的定义:当类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示;
@Scope
@Scope同样用于自定义注解,我能可以通过@Scope自定义的注解来限定注解作用域,实现局部的单例;
@Singleton
@Singleton其实就是一个通过@Scope定义的注解,我们一般通过它来实现全局单例。但实际上它并不能提前全局单例,是否能提供全局单例还要取决于对应的Component是否为一个全局对象。一般我们会自定义一个 注解
Dagger2 常见注解的英用:
1、@component
举例(一): 用户上班使用电脑工作:
创建 component(需求方和依赖放的桥梁 必须存在):
@Component
public interface WorkComponent {
User inject();
}
2、 @Inject
创建User:
public class User {
Computer computer;
@Inject
public User(Computer computer) {
this.computer = computer;
}
public void doWork(){
computer.doWork();
}
}
创建computer:
public class Computer {
@Inject
public Computer() {
}
public void doWork(){
Log.i("grage","doWork");
}
}
这个例子很简单,编码是computer 本身具有的行为,我们只是调用者
执行程序:
User user1 = DaggerWorkComponent.builder().build().inject();
user1.doWork();
//打印
I/grage: doWork
通过Inject 标注构造方法,dagger2 给我们创建了被Inject 标注的构造函数的实例:
DaggerWorkComponent 核心方法:
@Override
public User inject() {
return new User(new Computer());
}
举例二:添加一个module (我们的工具集)去调用不同的设备(printer)
3、 @Module、@Provider
1、添加module
@Module
public class WorkTools {
@Provides
public Printer providerPrinter(){
return new Printer();
}
}
2、修改component:
DaggerWorkComponent.builder().workTools(new WorkTools()).build().inject(this);
3、调用:
@Inject
Printer printer;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
DaggerWorkComponent.builder().workTools(newWorkTools()).build().inject(this);
printer.work();
//I/grage: print
注意:在component inject 方法必须注入参数,且和返回值只能存在一个
4、@Qualifier
举例三、假如我们有两台打印机呢,一台白色打印机,一台黑色打印机该怎么处理?
这次我们用到了@Qualifier
定义白色和黑色打印机 Qualifier
@Qualifier
public @interface BlackPrinter {
}
@Qualifier
public @interface WhitePrinter {
}
修改module:
@Module
public class WorkTools {
@Provides
@BlackPrinter
public Printer providerBlackPrinter(){
return new Printer("黑色");
}
@Provides
@WhitePrinter
public Printer providerWhitePrinter(){
return new Printer("白色");
}
}
修改printer
public class Printer {
private String color;
@Inject
public Printer(String color) {
this.color = color;
}
public void work(){
Log.i("grage",color +" print");
}
}
调用:
@Inject
@BlackPrinter
Printer blackPrinter;
@Inject
@WhitePrinter
Printer whitePrinter;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
DaggerWorkComponent.builder().workTools(new WorkTools()).build().inject(this);
blackPrinter.work();
whitePrinter.work();
}
//2020-06-13 13:05:35.735 15055-15055/union.com.myapplication I/grage: 黑色 print
//2020-06-13 13:05:35.735 15055-15055/union.com.myapplication I/grage: 白色 print
5、@Singleton
未添加 @singleton
修改代码:
@Inject
@BlackPrinter
Printer blackPrinter1;
@Inject
@BlackPrinter
Printer blackPrinter2;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
DaggerWorkComponent.builder().workTools(new WorkTools()).build().inject(this);
Log.i("grage","blackPrinter1="+blackPrinter1); //blackPrinter1=union.com.myapplication.lesson1.Printer@9fc99b4
Log.i("grage","blackPrinter2="+blackPrinter2);
// blackPrinter2=union.com.myapplication.lesson1.Printer@c9a79dd
}
可以看到这两个对象不是同一个:
添加 @Singleton 注解;
@Singleton
@Component(modules = {WorkTools.class, UserModule.class})
public interface WorkComponent {
void inject(MainActivity mainActivity);
}
@Module
public class WorkTools {
@Singleton
@Provides
@BlackPrinter
public Printer providerBlackPrinter(){
return new Printer("黑色");
}
@Singleton
@Provides
@WhitePrinter
public Printer providerWhitePrinter(){
return new Printer("白色");
}
}
@Inject
@BlackPrinter
Printer blackPrinter1;
@Inject
@BlackPrinter
Printer blackPrinter2;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
DaggerWorkComponent.builder().workTools(new WorkTools()).build().inject(this);
Log.i("grage","blackPrinter1="+blackPrinter1); //blackPrinter1=union.com.myapplication.lesson1.Printer@9fc99b4
Log.i("grage","blackPrinter2="+blackPrinter2);
// blackPrinter2=union.com.myapplication.lesson1.Printer@9fc99b4
}