If you want to pass parameters dynamically when building a Component, you need to add a method to the Component Builder and annotate @bindsInstance to inject instances into the Component.

CarComponent:

@Component(modules = {WheelModel.class})
public interface CarComponent {
    BMW makeBmw(a);

    @Component.Builder
    interface Builder {
        @BindsInstance Builder injectWheel(BMWWheel wheel);

        CarComponent build(a); }}Copy the code

WheelModel:

@Module
abstract class WheelModel {
     @Binds abstract IWheel provideWheel(BMWWheel wheel);
}
Copy the code

BMWWheel:

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

BMW:

public class BMW {
    @Inject
    public BMW(a) {
        super(a); }@Inject
    IWheel wheel;
}
Copy the code

Testing:

public class CarMain {
    public static void main(String[] args) {
        BMWWheel w = newBMWWheel(); CarComponent component = DaggerCarComponent.builder().injectWheel(w).build(); BMW bmw = component.makeBmw(); System.out.println(w); System.out.println(bmw.wheel); }}Copy the code

Obviously, the printed object is the same, indicating that the external object instance injected through @bindsInstance has been injected into the corresponding object through the Module class.

What happens if inejctWheel() is not called?

public class CarMain {
    public static void main(String[] args) {
        BMWWheel w = newBMWWheel(); CarComponent component = DaggerCarComponent.builder().build(); BMW bmw = component.makeBmw(); System.out.println(w); System.out.println(bmw.wheel); }}Copy the code

Results: the compiler error – Java. Lang. An IllegalStateException: com. Hero. BMWWheel must be set.

The reason for throwing an exception:

public final class DaggerCarComponent implements CarComponent {
/ / * * *
  private static final class Builder implements CarComponent.Builder {
    private BMWWheel injectWheel;

    @Override
    public Builder injectWheel(BMWWheel wheel) {
      this.injectWheel = Preconditions.checkNotNull(wheel);
      return this;
    }

    @Override
    public CarComponent build(a) {
      Preconditions.checkBuilderRequirement(injectWheel, BMWWheel.class);
      return newDaggerCarComponent(injectWheel); }}}Copy the code

As you can see, when the build() method is called, it determines whether the injected object is empty and throws an exception if it is.

So, is the object instance injected via @bindsInstance nullable?

Just add @nullable to the injected object.

WheelModel:

@Module
abstract class WheelModel {
    @Nullable @Binds abstract IWheel provideWheel(@Nullable BMWWheel wheel);
}
Copy the code

The Module class provides nullable objects.

BMW:

public class BMW {
    @Inject
    public BMW(a) {
        super(a); }@Inject
  	@Nullable
    IWheel wheel;
}
Copy the code

The wheel object that needs to be injected in BMW is also nullable.

CarComponent:

@Component(modules = {WheelModel.class})
public interface CarComponent {
    BMW makeBmw(a);

    @Component.Builder
    interface Builder {
        @BindsInstance Builder injectWheel(@Nullable BMWWheel wheel);

        CarComponent build(a); }}Copy the code

The @bindsinstance annotation is also nullable.

Make the incoming instance Nullable by adding the @nullable annotation.

However, by doing so, instances of objects that need to be injected must be provided externally rather than generated by Dagger2, which is inconvenient in some scenarios. It seems to be set up to use Dagger2 to generate object instances that are more flexible if there is no external setting. This, however, would make it meaningless to pass external control if the instance generated by Dagger2 makes the variable non-null.

Implementation principle:

DaggerCarComponent:

public final class DaggerCarComponent implements CarComponent {
  private final BMWWheel injectWheel;

  private DaggerCarComponent(BMWWheel injectWheelParam) {
    this.injectWheel = injectWheelParam;
  }

  public static CarComponent.Builder builder(a) {
    return new Builder();
  }

  @Override
  public BMW makeBmw(a) {
    returninjectBMW(BMW_Factory.newInstance()); }private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectWheel(instance, injectWheel);
    return instance;
  }

  private static final class Builder implements CarComponent.Builder {
    private BMWWheel injectWheel;

    @Override
    public Builder injectWheel(BMWWheel wheel) {
      this.injectWheel = wheel;
      return this;
    }

    @Override
    public CarComponent build(a) {
      return newDaggerCarComponent(injectWheel); }}}Copy the code

As you can see, the @bindsInstance annotation injectWheel() injectWheel() is passed to the DaggerCarComponent as a member variable when build() is called. Finally, the instance passed in from the outside is used directly when the DEPENDENCY is injected into the BMW object. It looks like the implementation is relatively simple.