Dagger

Dagger

依赖注入(Dependency Injection),简称DI,又叫控制反转(Inversion of Control),简称IOC
当一个类的实例需要另一个类的实例,在传统的设计中,通常由调用者来创建被调用者的实例,然而依赖注入的方式,创建被调用者不再由调用者创建实例,创建被调用者的实例的工作由IOC容器来完成,然后注入到调用者。因此也被称为依赖注入

  • API
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public @interface Component {
    Class<?>[] modules() default {};
    Class<?>[] dependencies() default {};
    @Target(TYPE)
    @Documented
    @interface Builder {}
    }

    public @interface Subcomponent {
    Class<?>[] modules() default {};
    @Target(TYPE)
    @Documented
    @interface Builder {}
    }

    public @interface Module {
    Class<?>[] includes() default {};
    @Beta
    Class<?>[] subcomponents() default {};
    }

    public @interface Provides {
    }

    public @interface MapKey {
    boolean unwrapValue() default true;
    }

    public interface Lazy<T> {
    T get();
    }
  • @Inject声明依赖注入构造方法,自动请求参数并调用构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     class Thermosiphon implements Pump {
    private final Heater heater;

    @Inject
    Thermosiphon(Heater heater) {
    this.heater = heater;
    }

    ...
    }
  • @Inject fields 实例化成员变量
    如果你的类有@Inject成员变量,但是没有@Inject构造方法,Dagger会注入这些变量,但是不会创建新的对象。所有添加@Inject无参的构造函数让Dagger也可以创建对象,也可以@Inject method(),当然Field,Constructor是首选。

    1
    2
    3
    4
    5
     class CoffeeMaker {
    @Inject Heater heater;
    @Inject Pump pump;
    ...
    }
  • @Inject不足

    1
    2
    3
    4
    类中只能包含一个@Inject constructor
    接口,抽象类是没有构造方法的
    第三方库提供的类,它们的构造方法不能被注解
    有些类需要灵活选择初始化的配置,而不是使用一个单一的构造方法
  • @Provides 可以满足上面的依赖性,但是必须属于一个Module,有一个惯例方法前缀加provide,类后缀加Module

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     @Module
    class DripCoffeeModule {
    @Provides static Heater provideHeater() {
    return new ElectricHeater();
    }

    @Provides static Pump providePump(Thermosiphon pump) {
    return pump;
    }
    }
  • @Component 在接口中,传入Module,完成接口和类的注入,将CoffeeShop 通过DripCoffeeModule注入到MainActivity中
    @Component中使用modules,表明该Component在哪些注入的Module中查找依赖
    @Component中使用dependencie,表明该Component在哪些注入的Component中查找依赖
    添加注入方法,一般使用inject
    可以声明方法,提供注入的实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     @Component(modules = DripCoffeeModule.class)
    interface CoffeeShop {
    CoffeeMaker maker();
    }

    CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
    .dripCoffeeModule(new DripCoffeeModule())
    .build();


    //如果@Component不是在类的上方,生成组件时需要添加下划线
    class Foo {
    static class Bar {
    @Component
    interface BazComponent {}
    }
    }
    DaggerFoo_Bar_BazComponent
  • 如果所有的依赖关系都可以在不需要实例对象的情况下创建,那么可以使用builder(),也可以使用crete()创建实例,对于所有的@Provides方法都是静态的Module,可以不需要考虑builder

    1
    CoffeeShop coffeeShop = DaggerCoffeeShop.create();
  • 针对在MainActivity中的依赖注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     public class Car {
    @Inject
    public Car() {
    }

    public String show() {
    return String.valueOf(1);
    }
    }

    @Component
    public interface MainActivityComponent {
    void inject(MainActivity activity);
    }

    public class MainActivity extends AppCompatActivity {
    @Inject
    Car car;
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 先编译一次crtl+F9
    DaggerMainActivityComponent.create().inject(this);
    String show = car.show();
    Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show();
    }
    }

    //Water 抽象类,@Inject无法提供实例
    @Inject
    public Car(Water water) {
    }

    //清除子类@Inject
    //@Inject
    public HotWater(){

    }
    // @Inject
    public CoolWater(){

    }
    /**
    *@Module标记在类上面
    *@Provodes标记在方法上
    *表示可以通过这个方法获取依赖
    */
    @Module
    public class WaterModule {
    @Provides
    Water provideWater(){
    return new HotWater();
    }
    }


    /**
    * 在Component中指定Module
    */
    @Component(modules = WaterModule.class)
    public interface MainActivityComponent {
    void inject(MainActivity mainActivity);
    }
  • @Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了Module
    @Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject可以提供依赖,@Component可以指定多个@Module的
  • Component可以包含多个Module或者Component,这样Component获取依赖时候会自动从多个Module中查找获取,但是,Module间不能有重复方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    在Component中的modules属性中注入多个Module

    @Component(modules={ModuleA.class,ModuleB.class,...})
    public interface FruitComponent{
    ...
    }
    在Component中的dependencies属性中注入多个依赖的Component

    @Component(dependencies={ComponentA.class,ComponentB.class,...})
    public interface FruitComponent{
    ...
    }
    在Module中注入多个Module

    @Module(includes={ModuleA.class,ModuleB.class,...})
    public class FruitModule{
    ...
    }
  • 注入的Module,不管是属于Component本身还是注入的Module的依赖,如果其构造函数为有参构造函数,必须进行初始化

    1
    2
    3
    DaggerFruitComponent.builder()
    .orangeModule(new OrangeModule(new OrangeBean("贡菊", 6.88, "江西南昌")))
    .build();
  • 依赖规则
    步骤1:查找Module中是否存在创建该类的方法。

    步骤2:若存在创建类方法,查看该方法是否存在参数
    步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
    步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入结束

    步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数
    步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
    步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入结束

  • 在Component中,可以声明方法,比如makeApple(),直接提供注入对象实例。DaggerFruitComponent针对每一个@Provides方法创建Provider\<T>实例。在调用makeApple()方法时,实际上是调用的相应Provider的get()方法,获取相应的实例

    1
    2
    3
    public AppleBean makeApple() {
    return provideAppleProvider.get();
    }
  • 依赖对象的注入源应该是有两个,一是Module中的@Provides方法,二是使用@Inject注解的构造函数

  • 单例@Singleton,可以做文档注释,提醒是线程安全

    1
    2
    3
     @Provides @Singleton static Heater provideHeater() {
    return new ElectricHeater();
    }
  • @Qualifier是限定符,而@Named则是基于String的限定符,容易写错,推荐@Qualifier 自定义注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
       @Provides
    @CoolQualifier
    // @Named("Cool")
    Water provideCoolWater() {
    return new CoolWater();
    }

    // 另外的一种方式,这里Water是抽象类,可以考虑其他对象Light灯光
    // @Provides
    // Water providePot(@CoolQualifier Water w) {
    // return new Water(w);
    // }
  • @Component与@SubComponent

    • Car

      1
      2
      3
      4
      5
      @Inject
      public Car(Water water) {
      this.water = water;
      oil = new Oil();
      }
    • WaterComponent

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
       /**
      * @Module标记在类上面
      * @Provodes标记在方法上 表示可以通过这个方法获取依赖
      */
      @Component(modules = WaterModule.class)
      public interface WaterComponent {
      @HotQualifier
      Water getHotWater();

      @CoolQualifier
      Water getCoolWater();
      }
    • CarModule

      1
      2
      3
      4
      5
      6
      7
       @Module
      public class CarModule {
      @Provides
      Car provideCar(@CoolQualifier Water water){
      return new Car(water);
      }
      }
    • CarComponent

      1
      2
      3
      4
      5
      6
      7
      8
       /**
      * @Module标记在类上面
      * @Provodes标记在方法上 表示可以通过这个方法获取依赖
      */
      @Component(modules = CarModule.class, dependencies = WaterComponent.class)
      public interface CarComponent {
      Car getCar();
      }
    • MainActivityComponent

      1
      2
      3
      4
       @Component(dependencies = CarComponent.class)
      public interface MainActivityComponent {
      void inject(MainActivity mainActivity);
      }
    • MainActivity

      1
      2
      3
      4
      5
      6
      7
      DaggerMainActivityComponent.builder()
      .carComponent(DaggerCarComponent.builder()
      .waterComponent(DaggerWaterComponent.create())
      .build())
      .build()
      .inject(this);
      Log.e(TAG, car.show());
    • CarComponent依赖WaterComponent,将WaterComponent的引用传递给CarComponent,这样CarComponent就可以使用WaterComponent中的方法。
      在DaggerCarComponent中的getCar()方法,waterComponent.getCoolWater()获取Water
    • 通过@SubComponent实现

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      @Component(modules = WaterModule.class)
      public interface WaterComponent {
      CarComponent plus(CarModule carModule);
      }

      @Subcomponent(modules = CarModule.class)
      public interface CarComponent{
      MainActivityComponent plus();
      }

      @Subcomponent
      public interface MainActivityComponent {
      void inject(MainActivity mainActivity);
      }
    • Component和SubComponent区别

      1
      2
      3
      4
      Component dependencies 能单独使用,而Subcomponent必须由Component调用方法获取。
      Component dependencies 可以很清楚的得知他依赖哪个Component, 而Subcomponent不确定
      使用上的区别,Subcomponent就像这样DaggerAppComponent.plus(new SharePreferenceModule());
      使用Dependence可能是这样DaggerAppComponent.sharePreferenceComponent(SharePreferenceComponent.create())
  • @Scope和@Singleton
    @Scope管理依赖的生命周期,@Scope对某类注解后,其作用的核心应该是注入器的控制,注入实例时,控制注入器调用缓存的实例还是重新实例,自定义注解,而@Singleton是@Scope默认实现
    如果有类注入实例的类被@Scope注解,那么其Component必须被相同的Scope注解

    1
    2
    3
    4
    @Scope
    @Documented
    @Retention(RUNTIME)
    public @interface Singleton {}
  • 依赖实例的注入来源是@Provides方法时,@Provides方法必须被@Scope注解;如果依赖实例的注入来源是@Inject注解的构造函数时,实例类必须被@Scope注解。这样@Scope注解才会有效。也就是说,@Scope实际上是对注入器的控制

    • Scope控制的实例的注入器是当前Component之内的实例注入器,而不会影响其他的Component中的实例注入器

    • 更好的管理Component之间的组织方式,用自定义的Scope注解标注这些Component,检查有依赖关系或包含关系的Component,若发现Component没有用自定义Scope注解标注,则会报错

    • 编译器会检查 Component管理的Modules,标注Component的自定义Scope注解与Modules中的标注创建类实例方法的注解不一样会报错
  • 单例实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Inject
    Car car1;
    //可以注入多个Car,但是重新创建了一个依赖
    @Inject
    Car car2;
    //使用单例,@Singleton
    @Module
    public class CarModule {
    @Provides
    @Singleton
    Car provideCar(@CoolQualifier Water water){
    return new Car(water);
    }
    }

    @Singleton
    @Component(modules = CarModule.class, dependencies = WaterComponent.class)
    public interface CarComponent {
    Car getCar();
    }
  • 编译报错

    1
    2
    Error:(16, 1) 错误: com.willkernel.www.daggerdemo.component.MainActivityComponent (unscoped) cannot depend on scoped components:
    @Singleton com.willkernel.www.daggerdemo.component.CarComponent
  • 在Component中指定Module
    MainActivityComponent依赖CarComponent
    而dagger2规定使用单例的Component,子Component也必须标注@Scope
    但是不能标注@Singleton,不允许,单例依赖单例不符合设计原则
    需要自定义一个@Scope,例如ActivityScope
    @Singleton 需要在@Provide和@Component,还有MainActivityComponent中使用@Scope
    才能够顺利编译,保持局部单例
  • 可以注入多个Car,但是重新创建了一个依赖,使用单例后两个地址一样,
    但是在其他Activity中,地址又不一样,属于局部单例,在其他Activity重新
    创建了注入器Component,所以Car对象的地址改变了
  • Dagger正确使用单例
    依赖在Component中是单例的(供该依赖的provide方法和对应的Component类使用同一个Scope注解)
    对应的Component在App中只初始化一次,每次注入依赖都使用这个Component对象(在Application中创建该Component)

  • App

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class App extends Application {
    private CarComponent carComponent;

    @Override
    public void onCreate() {
    super.onCreate();
    carComponent = DaggerCarComponent.builder()
    .waterComponent(DaggerWaterComponent.create())
    .build();
    }

    public CarComponent getCarComponent() {
    return carComponent;
    }
    }
  • SecondActivity

    1
    2
    3
    4
    5
    6
    7
    8
    @Inject
    Car car3;

    DaggerSecondActivityComponent.builder()
    .carComponent(((App) getApplication()).getCarComponent())
    .build()
    .inject(this);
    Log.e(TAG, "car3=" + car3.hashCode());
  • 也可以通过ApplciationScope使用单例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    @Scope
    @Retention(RUNTIME)
    public @interface ApplicationScope {
    }

    public class App extends Application{
    @Inject
    Car car;

    @Override
    public void onCreate() {
    super.onCreate();
    DaggerAppComponent.builder().carComponent(DaggerCarComponent.builder() .waterComponent(DaggerWaterComponent.create()).build())
    .build()
    .inject(this);
    }

    public Car getCar() {
    return car;
    }


    在SecondeActivity中引用
    car6=((App)getApplication()).getCar();
    Log.e(TAG, "car6=" + car6.hashCode());
  • MapKey

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    @Component(modules = MapKeyModule.class)
    public interface MapComponent {
    Map<String, String> mapkey();
    }

    @Module
    public class MapKeyModule {
    @Provides
    @IntoMap
    @TestKey("foo")
    String provideFooKey() {
    return "foo value";
    }

    @Provides
    @IntoMap
    @TestKey("bar")
    String provideBarKey() {
    return "bar value";
    }
    }

    @MapKey(unwrapValue = true)
    public @interface TestKey {
    String value();
    }

    Map<String, String> map = DaggerMapComponent.create().mapkey();
    Log.e(TAG, "map " + map.toString());
  • Lazy
    通过Lazy提供的实例,在@Inject的时候并不初始化,而是使用的时候,主动调用其get方法来获取实例,并且会缓存该对象

    1
    2
    3
    4
    5
    @Inject
    Lazy<Car> carLazy;

    Car carL = carLazy.get();
    Log.e(TAG, "carL " + carL.show());
  • Provider
    有时您需要注入多个实例列表,而不是注入单个值。可以注入一个Provider ,而不只是T。
    当Provider 每次调用get()方法时,都会执行绑定逻辑并创建一个新的实例,地址不一样,但@Scope注解的类地址是一样的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @CoffeeScope
    public class CoffeeBean {

    @Inject
    public CoffeeBean() {
    Log.d("test", "Coffee()");
    }
    }

    @Inject
    Provider<CoffeeBean> mCoffeeBeanProvider

    CoffeeBean beanA = mCoffeeBeanProvider.get();
    CoffeeBean beanB = mCoffeeBeanProvider.get();
  • 多个元素绑定并注入到Set

    • 将单个元素注入到Set

      1
      2
      3
      4
      5
      6
      7
      @Module
      class MyModuleA {
      @Provides @IntoSet
      static String provideOneString(DepA depA, DepB depB) {
      return "ABC";
      }
      }
    • Set 注入到Set

      1
      2
      3
      4
      5
      6
      7
        @Module
      class MyModuleB {
      @Provides @ElementsIntoSet
      static Set<String> provideSomeStrings(DepA depA, DepB depB) {
      return new HashSet<String>(Arrays.asList("DEF", "GHI"));
      }
      }
    • 在Component中,表明注入到Set的实例的提供Module,声明setApple()方法,用来提供集合Set

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
        class Bar {
      @Inject Bar(Set<String> strings) {
      assert strings.contains("ABC");
      assert strings.contains("DEF");
      assert strings.contains("GHI");
      }
      }
      或者
      @Component(modules = {MyModuleA.class, MyModuleB.class})
      interface MyComponent {
      Set<String> strings();
      }

      @Test void testMyComponent() {
      MyComponent myComponent = DaggerMyComponent.create();
      assertThat(myComponent.strings()).containsExactly("ABC", "DEF", "GHI");
      }
  • 也可以通过Provider<Set> or Lazy<Set>来依赖注入实例,但是不能通过Set<Provider>>

  • 增加限定符@Qualifier

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Module
    class MyModuleC {
    @Provides @IntoSet
    @MyQualifier
    static Foo provideOneFoo(DepA depA, DepB depB) {
    return new Foo(depA, depB);
    }
    }

    @Module
    class MyModuleD {
    @Provides
    static FooSetUser provideFooSetUser(@MyQualifier Set<Foo> foos) { ... }
    }
  • 多个元素绑定并注入到Map
    在Module中的@Provides方法使用@IntoMap,同时指定该元素的Key(例如@StringKey(“foo”),@ClassKey(Thing.class),@IntKey(12),@LongKey(100L)),没有这个key时,返回null

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     @Module
    class MyModule {
    @Provides @IntoMap
    @StringKey("foo")
    static Long provideFooValue() {
    return 100L;
    }

    @Provides @IntoMap
    @ClassKey(Thing.class)
    static String provideThingValue() {
    return "value for Thing";
    }
    }

    @Component(modules = MyModule.class)
    interface MyComponent {
    Map<String, Long> longsByString();
    Map<Class<?>, String> stringsByClass();
    }

    @Test void testMyComponent() {
    MyComponent myComponent = DaggerMyComponent.create();
    assertThat(myComponent.longsByString().get("foo")).isEqualTo(100L);
    assertThat(myComponent.stringsByClass().get(Thing.class))
    .isEqualTo("value for Thing");
    }
    • 如果key是枚举或其他特定的类,使用@MapKey注解,自定义Key
    • 自定义枚举类型,数据包装类key
      如果不满足指定的返回类型,那么编译时会报错:
      基本数据类型
      String
      Class(参数化类,? extends Number)
      枚举类型
      注解类型
      以上数据类型的数组

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      enum MyEnum {
      ABC, DEF;
      }

      @MapKey
      @interface MyEnumKey {
      MyEnum value();
      }

      @MapKey
      @interface MyNumberClassKey {
      Class<? extends Number> value();
      }
    • 在Module中的@Prvoides使用@IntoMap,并指明key

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
       @Module
      class MyModule {
      @Provides @IntoMap
      @MyEnumKey(MyEnum.ABC)
      static String provideABCValue() {
      return "value for ABC";
      }

      @Provides @IntoMap
      @MyNumberClassKey(BigDecimal.class)
      static String provideBigDecimalValue() {
      return "value for BigDecimal";
      }
      }
    • 注入器Component

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
       @Component(modules = MyModule.class)
      interface MyComponent {
      Map<MyEnum, String> myEnumStringMap();
      Map<Class<? extends Number>, String> stringsByNumberClass();
      }

      @Test void testMyComponent() {
      MyComponent myComponent = DaggerMyComponent.create();
      assertThat(myComponent.myEnumStringMap().get(MyEnum.ABC)).isEqualTo("value for ABC");
      assertThat(myComponent.stringsByNumberClass.get(BigDecimal.class))
      .isEqualTo("value for BigDecimal");
      }
    • 组合的MapKey,设置unwrapValue的值为false,这样key值也可以是数组成员,key不唯一指定,可以有多个不同类型的key

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
       @MapKey(unwrapValue = false)
      @interface MyKey {
      String name();
      Class<?> implementingClass();
      int[] thresholds();
      }

      @Module
      class MyModule {
      @Provides @IntoMap
      @MyKey(name = "abc", implementingClass = Abc.class, thresholds = {1, 5, 10})
      static String provideAbc1510Value() {
      return "foo";
      }
      }

      @Component(modules = MyModule.class)
      interface MyComponent {
      Map<MyKey, String> myKeyStringMap();
      }
    • 使用MapKey,需要生成Mykey的静态方法,就需要使用@AutoAnnotation

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
       apt 被annotationProcessor替代
      apply plugin: 'com.neenbedankt.android-apt'
      classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

      annotationProcessor "com.google.auto.value:auto-value-annotations:1.5"
      implementation "com.google.auto.value:auto-value:1.5"

      @AutoAnnotation
      static MyKey createMyKey(String name, Class<?> implementingClass, int[] thresholds) {
      return new AutoAnnotation_MainActivity_createMyKey(name, implementingClass, thresholds);
      }

      MyKeyComponent myKeyComponent = DaggerMyKeyComponent.create();
      Log.e(TAG, "myKeyComponent "+myKeyComponent.myKeyStringMap()
      .get(createMyKey("abc", BigDecimal.class, new int[]{1, 2, 4})));
    • Mapkey的key在编译期间未知,就不能创建Mapkey的绑定,不过可以先设置绑定Set,再转换为Map绑定

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
       @Module
      class MyModule {
      @Provides @IntoSet
      static Map.Entry<Foo, Bar> entryOne(...) {
      Foo key = ...;
      Bar value = ...;
      return new SimpleImmutableEntry(key, value);
      }

      @Provides @IntoSet
      static Map.Entry<Foo, Bar> entryTwo(...) {
      Foo key = ...;
      Bar value = ...;
      return new SimpleImmutableEntry(key, value);
      }
      }

      @Module
      class MyMapModule {
      @Provides
      static Map<Foo, Bar> fooBarMap(Set<Map.Entry<Foo, Bar>> entries) {
      Map<Foo, Bar> fooBarMap = new LinkedHashMap<>(entries.size());
      for (Map.Entry<Foo, Bar> entry : entries) {
      fooBarMap.put(entry.getKey(), entry.getValue());
      }
      return fooBarMap;
      }
      }
    • Dagger并不会自动注入Map\<Foo,Provider\<Bar>>,也就意味着不会提供一个含有Provider值得Map。如果想要获取一个含有Provider的Map,需要在Map.Entry对象中包含Provider值,那么所获取的Map也就含有Provider

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      @Module
      class MyModule {
      @Provides @IntoSet
      static Map.Entry<Foo, Provider<Bar>> entry(
      Provider<BarSubclass> barSubclassProvider) {
      Foo key = ...;
      return new SimpleImmutableEntry(key, barSubclassProvider);
      }
      }

      @Module
      class MyProviderMapModule {
      @Provides
      static Map<Foo, Provider<Bar>> fooBarProviderMap(
      Set<Map.Entry<Foo, Provider<Bar>>> entries) {
      return ...;
      }
      }
  • 声明多重绑定@Multibinds-annotated,也可以使用@IntoSet,@IntoMap,@ElementsIntoSet,但是必须有一个

    1
    2
    3
    4
    5
    6
    7
    @Module
    abstract class MyModule {
    @Multibinds abstract Set<Foo> aSet();
    @Multibinds @MyQualifier abstract Set<Foo> aQualifiedSet();
    @Multibinds abstract Map<String, Foo> aMap();
    @Multibinds @MyQualifier abstract Map<String, Foo> aQualifiedMap();
    }
  • Set或Map多重绑定可以声明任意次数而不会发生错误。Dagger从不实现或调用任何@Multibinds方法
    添加返回空集合的@ElementsIntoSet方法

    1
    2
    3
    4
    5
    6
    7
    @Module
    class MyEmptySetModule {
    @Provides @ElementsIntoSet
    static Set<Foo> primeEmptyFooSet() {
    return Collections.emptySet();
    }
    }
  • 添加子组件方式

    • @Component的dependencies属性依赖父组件

      1
      2
      3
      4
       @Component(modules = OrangeModule.class, dependencies = FruitComponent.class)
      public interface OrangeComponent {
      ***
      }
    • @Module的Subcomponents添加子组件

      1
      2
      3
      4
      5
       @Module(subcomponents = AppleSubcomponent.class)
      public class FruitModule {

      ***
      }
  • @SubComponent声明子组件,需要提供@Subcomponent.Builder接口的Builder,build()来构建子组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Subcomponent(modules = RequestModule.class)
    interface RequestComponent {
    RequestHandler requestHandler();

    @Subcomponent.Builder
    interface Builder {
    Builder requestModule(RequestModule module);
    RequestComponent build();
    }
    }
  • 添加子组件到父组件,添加子组件类到父组件的@Module的subcomponents属性,然后父组件调用子组件的builder方法

    1
    2
    @Module(subcomponents = RequestComponent.class)
    class ServerModule {}
  • 父组件的注入器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Singleton
    @Component(modules = ServerModule.class)
    interface ServerComponent {
    RequestRouter requestRouter();
    }

    子组件实例注入
    @Singleton
    class RequestRouter {
    @Inject RequestRouter(
    Provider<RequestComponent.Builder> requestComponentProvider) {}

    void dataReceived(Data data) {
    RequestComponent requestComponent =
    requestComponentProvider.get()
    .data(data)
    .build();
    requestComponent.requestHandler()
    .writeResponse(200, "hello, world");
    }
    }
  • 子组件和作用域,如果没有作用域的绑定,每次注入都会重新创建独立的对象,但是如果有作用域绑定的对象,在作用域生命周期中绑定的对象实例是同一个

  • 子组件和父组件的作用域不能相同,比父组件的生命周期短,两个子组件有不同的作用域实例,即使他们的作用域注解相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Singleton @Component
    interface RootComponent {
    SessionComponent.Builder sessionComponent();
    }

    @SessionScope @Subcomponent
    interface SessionComponent {
    FooRequestComponent.Builder fooRequestComponent();
    BarRequestComponent.Builder barRequestComponent();
    }

    @RequestScope @Subcomponent
    interface FooRequestComponent {...}

    @RequestScope @Subcomponent
    interface BarRequestComponent {...}
  • 封装子组件
    在不同Service,不同界面,共享某些绑定,但是这些绑定中也有不需要的绑定实例,这时就需要使用子组件,对绑定实例进行细分

    • 应用ApplicationComponent,注入数据库实例

      1
      2
      3
      4
      5
         @Singleton
      @Component(modules = DatabaseModule.class)
      interface ApplicationComponent {
      Database database();
      }
    • 数据库模块,子组件为DatabaseComponent

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
       @Module(subcomponents = DatabaseComponent.class)
      class DatabaseModule {
      @Provides
      @Singleton
      Database provideDatabase(
      @NumberOfCores int numberOfCores,
      DatabaseComponent.Builder databaseComponentBuilder) {
      return databaseComponentBuilder
      .databaseImplModule(new DatabaseImplModule(numberOfCores / 2))
      .build()
      .database();
      }
      }
    • 数据库实现类模块

      1
      2
      3
      4
      5
      6
       @Module
      class DatabaseImplModule {
      DatabaseImplModule(int concurrencyLevel) {}
      @Provides DatabaseConnectionPool provideDatabaseConnectionPool() {}
      @Provides DatabaseSchema provideDatabaseSchema() {}
      }
    • 子组件

      1
      2
      3
      4
       @Subcomponent(modules = DatabaseImplModule.class)
      interface DatabaseComponent {
      @PrivateToDatabase Database database();
      }
  • 抽象工厂方法定义子组件

    • 扩展多重绑定

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      @Subcomponent(modules = DatabaseImplModule.class)
      interface DatabaseComponent {
      @PrivateToDatabase Database database();
      }

      @Module
      class ParentModule {
      @Provides @IntoMap
      @StringKey("one") static int one() {
      return 1;
      }

      @Provides @IntoMap
      @StringKey("two") static int two() {
      return 2;
      }

      @Provides @IntoSet
      static String a() {
      return "a"
      }

      @Provides @IntoSet
      static String b() {
      return "b"
      }
      }

      @Subcomponent(modules = ChildModule.class)
      interface Child {
      Map<String, Integer> map();
      Set<String> set();
      }

      @Module
      class ChildModule {
      @Provides @IntoMap
      @StringKey("three") static int three() {
      return 3;
      }

      @Provides @IntoMap
      @StringKey("four") static int four() {
      return 4;
      }

      @Provides @IntoSet
      static String c() {
      return "c"
      }

      @Provides @IntoSet
      static String d() {
      return "d"
      }
      }

      Parent parent = DaggerParent.create();
      Child child = parent.child();
      assertThat(parent.map().keySet()).containsExactly("one", "two");
      assertThat(child.map().keySet()).containsExactly("one", "two", "three", "four");
      assertThat(parent.set()).containsExactly("a", "b");
      assertThat(child.set()).containsExactly("a", "b", "c", "d");
    • 模块Module作为工厂方法的参数会在编译时报错,重复模块Module在依赖注入获取对象时引用是运行时错误

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      @Component(modules = {RepeatedModule.class, ...})
      interface ComponentOne {
      ComponentTwo componentTwo(RepeatedModule repeatedModule); // COMPILE ERROR!
      ComponentThree.Builder componentThreeBuilder();
      }

      @Subcomponent(modules = {RepeatedModule.class, ...})
      interface ComponentTwo { ... }

      @Subcomponent(modules = {RepeatedModule.class, ...})
      interface ComponentThree {
      @Subcomponent.Builder
      interface Builder {
      Builder repeatedModule(RepeatedModule repeatedModule);
      ComponentThree build();
      }
      }

      DaggerComponentOne.create().componentThreeBuilder()
      .repeatedModule(new RepeatedModule()) // UnsupportedOperationException!
      .build();
Dagger Android
  • 引入Dagger

    1
    2
    3
    4
    5
    6
    7
    // Dagger dependencies
    annotationProcessor "com.google.dagger:dagger-compiler:$rootProject.daggerVersion"
    provided 'org.glassfish:javax.annotation:10.0-b28'
    compile "com.google.dagger:dagger:$rootProject.daggerVersion"
    compile "com.google.dagger:dagger-android:$rootProject.daggerVersion"
    compile "com.google.dagger:dagger-android-support:$rootProject.daggerVersion"
    annotationProcessor "com.google.dagger:dagger-android-processor:$rootProject.daggerVersion"
  • @Binds
    注解委托绑定模块的抽象方法,例如绑定Random到SecureRandom模块

    1
    @Binds abstract Random bindRandom(SecureRandom secureRandom);
    • 是@Provides的替代方法,更高效
    • @Binds method
      必须是抽象方法
      必须是一个可以转换为返回值类型的参数,参数是返回值类型的子类或实现类,将返回值类绑定到参数类,将参数暴露为返回值类型,不需要实例化参数对象
      可以有限定符@Qualified和作用域@Scoped
      1
      2
      3
      4
      @Documented
      @Retention(RUNTIME)
      @Target(METHOD)
      public @interface Binds {}
  • @ContributesAndroidInjector
    注解的方法生成的返回值对应的AndroidInjector。该注入器是 dagger.Subcomponent的实现,而且是dagger.Module 的子Component
    用于注解返回具体的Android框架类型(例如:FooActivity、BarFragment、MyService等)的dagger.Module中的无参抽象方法

  • BindsInstance 标识组件或子组件的Builder方法,绑定对象到组件中的类

    1
    2
    3
    4
    5
    @Documented
    @Retention(RUNTIME)
    @Target(METHOD)
    @Beta
    public @interface BindsInstance {}
  • 注入实例
    由于DispatchingAndroidInjector在运行时由类查找相应的AndroidInjector.Factory,那么,在基类中,实现HasActivityInjector/HasFragmentInjector接口,在相应的声明周期(onCreate()或者onAttach())内调用AndroidInjection.inject()方法,注入相应的实例。所有每个子类都需要做的是绑定相应的@Subcomponent,从而没有必要在每个实例类中调用AndroidInjection.inject()方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Beta
    public abstract class DaggerActivity extends Activity implements HasFragmentInjector {

    @Inject DispatchingAndroidInjector<Fragment> fragmentInjector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
    }

    @Override
    public AndroidInjector<Fragment> fragmentInjector() {
    return fragmentInjector;
    }
    }
    • 在dagger.android库中,有一些基本类型,对于Appliaction是DaggerApplication,只需重写applicationInjectoer()方法来返回AndroidInjector\<XxApplication>
      Dagger提供的基本类型:
      DaggerActivity
      DaggerFragment
      DaggerService
      DaggerIntentService
      DaggerBroadcastReceiver
      DaggerContentProvider
willkernel wechat
关注微信公众号
帅哥美女们,请赐予我力量吧!