Components in Dagger2 cannot have the same type of provider: the @Inject annotated constructor and the @provides method annotated in the Module, otherwise there will be a dependency loss error. It is possible to provide different instances of the same type by using Qualifier.

Qualifier is an annotation class defined under Javax. inject that can be used on other annotations:

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

@ Named:

Dagger2 provides an @named annotation to mark different instances:

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

Use @named to tag the instance you want to inject. Use the build method in the @named annotation Module class.

BMWWheel:

public class BMWWheel implements IWheel {
    @Inject
    public BMWWheel(a) {
        super(a); }/ / * * *
}
Copy the code

Two iWheels are injected into BMW:

public class BMW {
    @Inject
    public BMW(a) {
        super(a); }@Inject
    IWheel rainWheel;


    @Inject
    IWheel sandWheel;
}
Copy the code

Two iWheels are provided to bind in WheelModel:

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

    @Binds
    abstract IWheel provideSandWheel(BMWWheel wheel);
}
Copy the code

[Dagger/DuplicateBindings] com.hero.iwheel is bound multiple times:

Solution: Add @named annotations to the two instances and methods in the Module class that need to be injected in BMW:

BMW:

public class BMW {
    @Inject
    public BMW(a) {
        super(a); }@Inject
    @Named("rain")
    IWheel rainWheel;


    @Inject
    @Named("sand")
    IWheel sandWheel;
}
Copy the code

WheelModel:

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

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

By adding the @named annotation, you implement the dependency of injecting different instances of the same type.

How it works: In the generated DaggerCarComponent class:

public final class DaggerCarComponent implements CarComponent {
/ / * * *
  @Override
  public BMW makeBmw(a) {
    returninjectBMW(BMW_Factory.newInstance()); }private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectRainWheel(instance, new BMWWheel());
    BMW_MembersInjector.injectSandWheel(instance, new BMWWheel());
    return instance;
  }
  / / * * *
}
Copy the code

As you can see, when creating a new BMW instance, different injection object methods are called to assign values to different variables.

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; }}Copy the code

Custom @ the Qualifier

Custom @rain and @sand:

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

Use on variables that need to be injected in BMW:

public class BMW {
    @Inject
    public BMW(a) {
        super(a); }@Inject
    @Rain
    IWheel rainWheel;


    @Inject
    @Sand
    IWheel sandWheel;
}
Copy the code

Use on methods that provide dependencies in the Module class:

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

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

}
Copy the code

The effect is similar to @named, with two variables of the same type in BMW getting dependency injection.

The implementation principle is similar to @named. Dagger2 generates member variable injection classes that generate different methods to complete the corresponding variable injection.

Is it different if the Module class is held not @ Binding but @Provides?

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

    @Provides
    @Sand
    public IWheel provideSandWheel(BMWWheel wheel) {
        return newBMWWheel(); }}Copy the code

The process of variable injection is no different from @ Cursor-Binding:

public final class DaggerCarComponent implements CarComponent {
  / / * * *
    private IWheel getSandIWheel(a) {
    return WheelModel_ProvideSandWheelFactory.provideSandWheel(wheelModel, newBMWWheel()); }@Override
  public BMW makeBmw(a) {
    returninjectBMW(BMW_Factory.newInstance()); }private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectRainWheel(instance, WheelModel_ProvideRainWheelFactory.provideRainWheel(wheelModel));
    BMW_MembersInjector.injectSandWheel(instance, getSandIWheel());
    return instance;
  }
    / / * * *
}
Copy the code

Dagger2 Provides a factory class for each @provides method to provide object instances:

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

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

  @Override
  public IWheel get(a) {
    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"); }}Copy the code

WheelModel_ProvideRainWheelFactory is used to create BMWWheel instances annotated by @rain

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(a) {
    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"); }}Copy the code

WheelModel_ProvideSandWheelFactory is used to create BMWWheel instances annotated by @SAND.