这篇文章主要记录一下Dagger 2的使用,详情Dagger 2 官方文档
dagger 2 是一款依赖注入框架,通俗的就是一个类中的属性对象(组合)通过框架注入而无需显示调用 new Object ,主要的好处就是解耦,降低两个类的关联.
1. @Inject
-
提供实例的类的是默认的构造函数
- @Inject 注解在一个 Filed 域. 表示在 MainActivity类中注入一个 Engine 对象
public class MainActivity extends AppCompatActivity {
// 这个 @Inject 表示要注入一个 Engine对象
@Inject Engine mEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.create().inject(this);
}
public void onClick(View view) {
Toast.makeText(this,mEngine.toString(),Toast.LENGTH_SHORT).show();
}
}
- @Inject 注解在一个 构造函数中,表示可以提供该类的实例供注入别的类中 ,有且只有一个Engine 的构造函数能被 @Inject 标注
public class Engine {
private String model;
private int age;
// 提供 Engine 对象
@Inject
public Engine() {
model = "xxxx";
age = 1990;
}
public Engine(String model, int age) {
this.model = model;
this.age = age;
}
@Override
public String toString() {
return "Engine{" +
"model='" + model + '\'' +
", age=" + age +
'}';
}
}
- 定义一个接口并用 @Component 标注
用来把 Engine 注入到 MainActivity 中
@Component
public interface MainComponent {
/**
* 必须让Component知道需要往哪个类中注入,这个方法名可以是其它的,但是推荐用inject
* 目标类MainActivity必须精确,不能用它的父类
*/
void inject(MainActivity activity);
}
- 在 MainActivity 中 onCreate 方法中调用
// DaggerMainComponent 这个类是 Dagger 框架自动生成的辅助类,
DaggerMainComponent.create().inject(this);
之后就可以使用 mEngine 这个对象了,框架是通过调用 Engine 的构造函数生成了一个 Engine 对象 并注入了 MainActivity
-
注入的对象构造函数有参数,也需要提供参数对象
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);
}
public void onClick(View view) {
Toast.makeText(this,mCar.toString(),Toast.LENGTH_SHORT).show();
}
}
dagger 框架会直接通过 Engine Tire的被 @Inject 的构造函数提供 Car 构造函数的参数对象
public class Car {
private Engine mEngine;
private Tire mTire;
@Inject
public Car(Engine engine,Tire tire) {
mEngine = engine;
mTire = tire;
}
@Override
public String toString() {
return "Car{" +
"mEngine=" + mEngine +
", mTire='" + mTire + '\'' +
'}';
}
}
Engine对象见 1.2
public class Tire {
private int radius;
// 提供 Car 构造函数的 Tire 对象
@Inject
public Tire() {
radius = 80;
}
@Override
public String toString() {
return "Tire{" +
"radius=" + radius +
'}';
}
}
@Inject无法满足所有的要求 :
- 接口无法被构造.
- 引用的第三方框架对象无法被注解.
- 可配置的对象无法被配置,只能使用构造函数构造
2. 使用 @Module @Provides
@Inject的局限性, Dagger 提供了另外一套提供实例的办法
@Module
public class TireModule {
//可以提供一个 Tire 对象实例
@Provides
public static Tire provideTire()
{
return new Tire();
}
}
@Module
public class EngineModule {
// 可以提供一个 Engine 对象实例
@Provides
public static Engine provideEngine()
{
return new Engine("F1234",2018);
}
}
@Component(modules = {TireModule.class,EngineModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
当要注入 Car 现在构造函数有两个地方可以提供 Engine Tire对象作为 Car 构造函数的参数
- @Inject 标注的构造函数提供
- @Module @Provides 提供
Dagger 优先使用 @Module @Provides 提供的对象.
- 利用 @Module @Provides 也可以直接提供 Car 对象
3. @Scope:作用域 并不使用在类中,用于定义注解
@Scope的作用主要是在组织Component和Module的时候起到一个实例作用范围的提醒(类似是生命周期)
-
已经定义好的作用域 @Singleton
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
@Provides 加上 @Singleton 表明会使用相同的 Car 对象去初始化所有需要 Car 对象的客户端
@Module
public class CarModule {
@Provides
@Singleton
public static Car provideCar1()
{
return new Car(new Engine("F-7890",2020),new Tire());
}
}
Component的也必须标注 @Singleton 不然会编译报错,作用域不匹配
@Component(modules = CarModule.class)
@Singleton
public interface MainComponent {
Car maker();
}
public class MainActivity extends AppCompatActivity {
private Car car1;
private Car car2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainComponent component = DaggerMainComponent.create();
car1=component.maker();
car2=component.maker();
}
public void onClick(View view) {
Toast.makeText(this," car1==car2 : "+(car1==car2),Toast.LENGTH_SHORT).show();
}
}
car1 = car : true
若去掉 @Singleton 注解结果为 false
@Singleton并不是我们传统单例模式的那种作用,只能保证在一个Component当中只提供同一个实例对象 但并不是整个的应用全局只有一个对象,调用DaggerMainComponent.create()两次产生两个 MainComponent对象也会产生两个Car对象,要保证应用全局单例可以配合android中application的特殊性,就可以实现应用全局单例
Module中的方法 使用@Singleton标注后,那对应的Component也必须采用@Singleton标注,表明它们的作用域一致,否则编译的时候会报作用域不同的错误。
-
自定义作用域
@ActivityScoped是一个自定义的作用域注解,作用是允许对象被记录在正确的组件中,当然这些对象的生命周期应该遵循activity的生命周期
@Documented
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScoped {
}
@FragmentScoped是一个自定义的作用域注解,作用是允许对象被记录在正确的组件中,当然这些对象的生命周期应该遵循Fragment的生命周期
@Scope
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface FragmentScoped {}
4. @Qualifier:限定符 并不使用在类中,用于定义注解
-
定义好的限定符 @Named
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}
@Named("provideCar2")
@Inject Car mCar;
在宿主中使用时,可以通过 @Named 来选择所需要的那个实例
@Module
public class CarModule {
@Provides
public static Car provideCar1()
{
return new Car(new Engine("F-7890",2020),new Tire());
}
@Provides
@Named("provideCar2")
public static Car provideCar2()
{
return new Car(new Engine("X-7890",2030),new Tire());
}
}
@Component(modules = CarModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
-
自定义限定符
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ForTest {
}
5. @Binds
@Binds 可以用于当需要一个父类对象时,用子类对象进行替代 (接口同理)
public class Car {
}
public class BenzCar extends Car {
@Inject
public BenzCar() {
}
}
@Module
public abstract class CarModule {
@Binds
abstract Car provideCar(BenzCar car);
}
@Component(modules = CarModule.class)
public interface MainComponent {
Car maker();
}
public class MainActivity extends AppCompatActivity {
@Inject
Car car;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
car=DaggerMainComponent.create().maker();
}
public void onClick(View view) {
Toast.makeText(this,car.getClass().getSimpleName(),Toast.LENGTH_SHORT).show();
}
}
结果为 :
BenzCar
通过 @Binds 当需要注入一个 Car 对象 可以使用子类对象 BenzCar 进行绑定注入
6. @BindsInstance
上述注入对象都是通过 Dagger 自动注入的,如果我们需要 new 一个对象传入 Dagger 就可以使用 @BindsInstance
public class Car {
private Engine mEngine;
private Tire mTire;
// 提供一个 Car 对象,但是需要 Engine Tire对象作为参数
@Inject
public Car( Engine engine, Tire tire) {
mEngine = engine;
mTire = tire;
}
}
public class Engine {
private String model;
private int age;
public Engine(String model, int age) {
this.model = model;
this.age = age;
}
}
public class Tire {
private int radius;
// Tire 不提供对象,手动注入
public Tire(int radius) {
this.radius = radius;
}
}
@Module
public class EngineModule {
// 提供 Engine 对象
@Provides
public static Engine provideEngine()
{
return new Engine("F1234",2018);
}
}
@Component.Builder 注明一个 MainComponent builder @BindsInstance 定义一个传入手动对象的方法
@Component(modules = EngineModule.class)
public interface MainComponent {
Car maker();
@Component.Builder
interface Builder {
@BindsInstance
Builder tire(Tire tire);
MainComponent build();
}
}
要构造 Car 对象需要 Engine Tire对象 ,Engine对象框架自动生成, Tire对象由我们手动传入
public class MainActivity extends AppCompatActivity {
@Inject
Car car;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 手动注入 Tire 对象
car=DaggerMainComponent.builder().tire(new Tire(90)).build().maker();
}
public void onClick(View view) {
Toast.makeText(this,car.toString(),Toast.LENGTH_SHORT).show();
}
}
7. Lazy 和 Provider
- Lazy
@Module
public class CarModule {
@Provides
public static Car provideCar1()
{
return new Car(new Engine("F-7890",2020),new Tire());
}
}
@Component(modules = CarModule.class)
public interface MainComponent {
Lazy maker();
}
public class MainActivity extends AppCompatActivity {
private Car car1;
private Car car2;
@Inject
Lazy mCarLazy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCarLazy=DaggerMainComponent.create().maker();
car1=mCarLazy.get();
car2=mCarLazy.get();
}
public void onClick(View view) {
Toast.makeText(this," car1==car2 : "+(car1==car2),Toast.LENGTH_SHORT).show();
}
}
car1 = car : true
当注入 Lazy
- Provider
**把上述的代码的 Lazy
car1 = car : false
当注入 Provider
如果 Provider
@Module
public class CarModule {
@Provides
@Singleton
public static Car provideCar1()
{
return new Car(new Engine("F-7890",2020),new Tire());
}
}
@Component(modules = CarModule.class)
@Singleton
public interface MainComponent {
Provider maker();
}
结果为 :
car1 = car : true
当注入 Provider