初识dagger(一)

依赖注入

依赖注入:在项目开发中,常见一个类的实例依赖另外一个类实例的状况 如java

public  class Man(){
	prviate Car car;
	public Man(){
		car=new Car();
	}
}
复制代码

常见的依赖方式基于构造方法,set设置等缓存

依赖注入是控制反转的一种表现形式,被依赖的对象(Car)再也不由 依赖对象(Man)主动建立 ,而是由第三方容器去建立,而后注入到依赖对象(man)的过程,下降代码耦合性bash

集成与使用

在build.gradle中添加依赖:ide

dependencies {
    ...
    implementation 'com.google.dagger:dagger:2.13'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.13'
}
复制代码

借助上面的场景进行应用测试

Car相关代码 因为Car须要被注入,在构造方法上增长 @Inject 注解gradle

public class Car {
  private CarDipan carDipan;

  @Inject
  public Car() {
  }

  public void pao() {
    System.out.println("跑起来");
  }
}
复制代码

Man相关代码 在Car变量上声明 @Inject 注解ui

public class Man {
  @Inject
  Car car;

  public Man() {
    //该行代码后面讲到
    DaggerManComponent.create().inject(this);
  }

  public void kaiche() {
    car.pao();
  }
}
复制代码

此时依赖和被依赖的类都建立好了,还缺乏一个纽带把他们链接起来,纽带就是 @Component
@Component 注解须要做用到接口或者抽象类上,添加抽象方法,参数是须要注入依赖的类,会自动生成以Dagger开头的实现类 在Man的构造方法中进行注入 DaggerManComponent.create().inject(this); (可能会报找不到该类,须要rebuild下) ManComponent代码以下this

@Component
interface ManComponent {
  void inject(Man man);
}

复制代码

测试代码google

public class DaggerTest {
  public static void main(String[] args) {
    Man man = new Man();
    man.kaiche();
  }
}
复制代码

Module和Provides注解

有一些第三方库,咱们没法修改源码,即没法用@Inject去注解构造方法。这时候就须要@Module和@Provides注解spa

  • @Module 注解到类上,表示这个类能够做为一个模块去引入到被@Component注解的接口上,规定用@Module注解的类名以Module作后缀
  • @Provides用于被@Module标注类的方法中,规定用provide做为前缀
    假设Man对象包含一个FangZi对象,该对象构造方法没法用@Inject注解标注,那么能够提供如下类
@Module
public class FangModule {
  @Provides
  public Fang provideFang() {
    return new Fang();
  }
}
复制代码

对应的ManComponent类也须要修改

@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}
复制代码

这样Man里面的房子属性就会成功注入。被注入的属性必定要用@Inject注解
Module类的构造方法能够带有参数,须要注意的是当Module类有带有参数的构造方法时, DaggerManComponent不会有Create方法,须要经过DaggerManComponent.builder().fangModule(new FangModule(参数)).build()手动传入module对象

Bind注解

Bind注解和Provides注意相似 ,也是放到被Module类的方法上,不一样的是Bind注解的方法是抽象方法,参数类型是返回值类型的子类。 用于注入某个接口或者抽象类时,能够获取他的实现子类。或者能够说将一种类型转换成他的父类或接口,只暴露父类或接口的方法

BindModule.java

@Module
public abstract class BindModule {
  @Binds
  public abstract Manger bindManager(ManagerImpl manager);
  
  public static abstract class Manger {
    public abstract String getName();
  }

  public static class ManagerImpl extends Manger {
    @Inject
    public ManagerImpl() {
    }

    @Override public String getName() {
      return "我是ManagerImpl";
    }
  }
}
Man.java

public class Man {

  @Inject
  BindModule.Manger manger;//这是获取的时他的子类MangerImpl

  public Man() {
    DaggerManComponent.create().inject(this);
  }

  public void run() {
    System.out.println(manger.getName());
  }
}
复制代码

Named、Singleton和Reusable

@Named 别名注解 和@Provides配合使用 好比我有两套房子,可是返回值都是房子 若是不用@Named注解,dagger不知道我们要哪一个房子,就会迷失,这时就须要起一个别名

@Module
public class FangModule {

  @Named("北三环")
  @Provides
  public Fang provideFang() {
    return new Fang("北三环");
  }
  @Named("西四环")
  @Provides
  public Fang provideFang2() {
    return new Fang("西四环");
  }
}
复制代码

在获取房子是就必须注明@Named 表示 要哪个

public class Man {
  @Inject
  Car car;
  @Named("北三环")
  @Inject
  Fang fang1;
  @Named("西四环")
  @Inject
  Fang fang2;
}
复制代码

@Qualifier 元注解 注解在@Named上 咱们能够用 Qualifier自定义和 @Named功能相同的 注解
@Singleton 单例注解 在一个Component组件中单例 Singleton标注在Component上 和 Provides标注的方法或者标注在要注入的类上。 实现机制 是经过DoubleCheck来保证单例,在生成的DaggerManComponent类的初始化中,会把Provider转换为DoubleCheck 在DoubleCheck的get方法中保证明例惟一

@Module
public class FangModule {
  @Singleton
  @Provides
  public Fang provideFang() {
    return new Fang("北三环");
  }
}
复制代码
@Singleton
@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}
复制代码

@Scope 元注解 注解在@Singleton 咱们能够用 @Scope自定义和 @Singleton功能相同的 注解
@Reusable 注解 有时咱们为了限制对象的建立次数,使用时能够从缓存中获取对象,可使用该注解 该注解标注在 Provides标注的方法或者标注在要注入的类上。 该机制会把Provider转换为SingleCheck来 使用SingleCheck来保证若是无对象会建立对象 若是有则会从缓存中获取

@Module
public class FangModule {
  @Reusable
  @Provides
  public Fang provideFang() {
    return new Fang("北三环");
  }
}
复制代码
@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}  
复制代码

Lazy和Provider

Lazy 有时候咱们不想运行时就把类建立好,而是在须要的时候建立类,这是就能够经过Lazy包装要被注入的成员 ,使用时经过get方式获取

public class Man {
  @Inject
  Lazy<Car> car;

  public Man() {
    DaggerManComponent.create().inject(this);
  }

  public void kaiche() {
    car.get().pao();
  }
} 
复制代码

Provider 有时咱们 须要建立类的多个实例,能够经过Provider包装要被注入的成员,每次执行get则会建立一个新的实例

IntoSet和IntoMap注解

IntoSet须要和Provides或Bind一块儿使用,咱们知道在Module中若是有两个方法返回值会致使依赖迷失,须要用Named注解起别名。 可是若是这些方法被@IntoSet注解修饰,相同的返回值产生的对象会被放到同一个Set集合中。同时注入该类对象时,须要用Set去包装

FangModule.java

@Module
public class FangModule {
  @IntoSet
  @Provides
  public Fang provideFang1() {
    return new Fang("国贸");
  }

  @IntoSet
  @Provides
  public Fang provideFang2() {
    return new Fang("望京");
  }
}

Man.java

public class Man {
  @Inject
  Set<Fang> fangs;

  public Man() {
    DaggerManComponent.builder().fangModule(new FangModule()).build().inject(this);
  }

  public void run() {
    fangs.forEach(Fang::get);
  }
}
复制代码

IntoMap和IntoSet相似,不过是将发返回的对象放入到map集合中。用IntoMap注解时, 必须指明Key.使用 @IntKey/ @LongKey/@StringKey注解 也可使用@MapKey元注解,自定义Key注解

相关文章
相关标签/搜索