Dagger2——Qualifiers

431 阅读3分钟

Dagger2中的组件中不能有相同类型的提供者:@Inject标注的构造函数和module中标注的@Provides的方法,否则就会出现依赖迷失的错误。通过使用Qualifier可以实现提供相同类型的不同实例。

@Qualifier是javax.inject下定义的一个注解类,可以用在其他注解上:

package javax.inject;
//***
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
}

@Named:

Dagger2提供了一个@Named注解用来标注不同的实例:

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
  String value() default "";
}

具体的用法:使用@Named标记需要注入的实例;使用@Named标注module类中的生成方法。

BMWWheel:

public class BMWWheel implements IWheel {
    @Inject
    public BMWWheel() {
        super();
    }
//***
}

在BMW中注入两种IWheel:

public class BMW {
    @Inject
    public BMW() {
        super();
    }

    @Inject
    IWheel rainWheel;


    @Inject
    IWheel sandWheel;
}

在WheelModel中提供绑定两种IWheel:

@Module
abstract class WheelModel {
    @Binds
    abstract IWheel provideRainWheel(BMWWheel wheel);

    @Binds
    abstract IWheel provideSandWheel(BMWWheel wheel);
}

编译后会提示: [Dagger/DuplicateBindings] com.hero.IWheel is bound multiple times:

解决办法:给BMW中需要注入的两个实例和module类中的方法增加相应的@Named注解:

BMW:

public class BMW {
    @Inject
    public BMW() {
        super();
    }

    @Inject
    @Named("rain")
    IWheel rainWheel;


    @Inject
    @Named("sand")
    IWheel sandWheel;
}

WheelModel:

@Module
abstract class WheelModel {
    @Binds
    @Named("rain")
    abstract IWheel provideRainWheel(BMWWheel wheel);

    @Binds
    @Named("sand")
    abstract IWheel provideSandWheel(BMWWheel wheel);
}

通过增加@Named注解,就实现了注入相同类型的不同实例的依赖关系。

实现原理:主要在生成的DaggerCarComponent类中:

public final class DaggerCarComponent implements CarComponent {
//***
  @Override
  public BMW makeBmw() {
    return injectBMW(BMW_Factory.newInstance());}

  private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectRainWheel(instance, new BMWWheel());
    BMW_MembersInjector.injectSandWheel(instance, new BMWWheel());
    return instance;
  }
  //***
}

可以看到,创建新的BMW实例时,会调用不同的注入对象的方法给不同的变量赋值。

BMW_MembersInjector:

public final class BMW_MembersInjector implements MembersInjector<BMW> {
  @Override
  public void injectMembers(BMW instance) {
    injectRainWheel(instance, rainWheelProvider.get());
    injectSandWheel(instance, sandWheelProvider.get());
  }

  @InjectedFieldSignature("com.hero.BMW.rainWheel")
  @Named("rain")
  public static void injectRainWheel(BMW instance, IWheel rainWheel) {
    instance.rainWheel = rainWheel;
  }

  @InjectedFieldSignature("com.hero.BMW.sandWheel")
  @Named("sand")
  public static void injectSandWheel(BMW instance, IWheel sandWheel) {
    instance.sandWheel = sandWheel;
  }
}

自定义@Qualifier

自定义@Rain和@Sand两个注解:

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Rain {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Sand {
}

在BMW中需要注入的变量上使用:

public class BMW {
    @Inject
    public BMW() {
        super();
    }

    @Inject
    @Rain
    IWheel rainWheel;


    @Inject
    @Sand
    IWheel sandWheel;
}

在module类中提供依赖的方法上使用:

@Module
abstract class WheelModel {
    @Binds
    @Rain
    abstract IWheel provideRainWheel(BMWWheel wheel);

    @Binds
    @Sand
    abstract IWheel provideSandWheel(BMWWheel wheel);

}

实现的效果与@Named类似,BMW中的两个相同类型的变量都得到了依赖注入。

实现原理与@Named类似,Dagger2生成的成员变量注入类会生成不同的方法来完成对应的变量注入。

如果module类中不使用@Binds而是@Provides,是否会有不同:

@Module
public class WheelModel {
    @Provides
    @Rain
    public IWheel provideRainWheel() {
        return new BMWWheel();
    }

    @Provides
    @Sand
    public IWheel provideSandWheel(BMWWheel wheel) {
        return new BMWWheel();
    }
}

变量注入的过程是跟@Binds没有区别:

public final class DaggerCarComponent implements CarComponent {
  //***
    private IWheel getSandIWheel() {
    return WheelModel_ProvideSandWheelFactory.provideSandWheel(wheelModel, new BMWWheel());}

  @Override
  public BMW makeBmw() {
    return injectBMW(BMW_Factory.newInstance());}

  private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectRainWheel(instance, WheelModel_ProvideRainWheelFactory.provideRainWheel(wheelModel));
    BMW_MembersInjector.injectSandWheel(instance, getSandIWheel());
    return instance;
  }
    //***
}

只是依赖提供的方式不太一样,Dagger2为每个@Provides方法提供了对应的工厂类用来提供对象实例:

public final class WheelModel_ProvideRainWheelFactory implements Factory<IWheel> {
  private final WheelModel module;

  public WheelModel_ProvideRainWheelFactory(WheelModel module) {
    this.module = module;
  }

  @Override
  public IWheel get() {
    return provideRainWheel(module);
  }

  public static WheelModel_ProvideRainWheelFactory create(WheelModel module) {
    return new WheelModel_ProvideRainWheelFactory(module);
  }

  public static IWheel provideRainWheel(WheelModel instance) {
    return Preconditions.checkNotNull(instance.provideRainWheel(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

WheelModel_ProvideRainWheelFactory用来创建被@Rain标注的BMWWheel实例

public final class WheelModel_ProvideSandWheelFactory implements Factory<IWheel> {
  private final WheelModel module;

  private final Provider<BMWWheel> wheelProvider;

  public WheelModel_ProvideSandWheelFactory(WheelModel module, Provider<BMWWheel> wheelProvider) {
    this.module = module;
    this.wheelProvider = wheelProvider;
  }

  @Override
  public IWheel get() {
    return provideSandWheel(module, wheelProvider.get());
  }

  public static WheelModel_ProvideSandWheelFactory create(WheelModel module,
      Provider<BMWWheel> wheelProvider) {
    return new WheelModel_ProvideSandWheelFactory(module, wheelProvider);
  }

  public static IWheel provideSandWheel(WheelModel instance, BMWWheel wheel) {
    return Preconditions.checkNotNull(instance.provideSandWheel(wheel), "Cannot return null from a non-@Nullable @Provides method");
  }
}

WheelModel_ProvideSandWheelFactory用来创建被@Sand标注的BMWWheel实例。