Dagger2——Binding Instances

395 阅读2分钟

如果要在构建Component时动态传参,那么需要在Component的builder中添加一个方法并用@BindsInstance标注,这样就能够向Component中注入实例。

CarComponent:

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

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

        CarComponent build();
    }
}

WheelModel:

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

BMWWheel:

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

BMW:

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

    @Inject
    IWheel wheel;
}

测试:

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

显然,两次打印的对象是同一个,说明通过@BindsInstance注入的外部对象实例已经通过Module类注入到了被对应的对象中。

如果不调用inejctWheel()会发生什么?

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

结果:编译出错——java.lang.IllegalStateException: com.hero.BMWWheel must be set。

抛出异常的原因:

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() {
      Preconditions.checkBuilderRequirement(injectWheel, BMWWheel.class);
      return new DaggerCarComponent(injectWheel);
    }
  }
}

可见,调用build()方法时,会判断注入的对象是否为空,如果为空,则抛出异常。

那么,通过@BindsInstance注入的对象实例是否可空。

只需要给注入的对象设置可空,即增加@Nullable即可。

WheelModel:

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

Module类提供的对象是可空的。

BMW:

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

    @Inject
  	@Nullable
    IWheel wheel;
}

BMW中需要注入的wheel对象也是可空的。

CarComponent:

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

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

        CarComponent build();
    }
}

@BindsInstance标注的方法,传入的参数也是可空的。

通过增加@Nullable注解,使得传入的实例可空。

但是这样做,使得对象中需要注入的实例必须由外部提供,而不是dagger2生成,某些场景下不太方便。似乎设置成,如果外部没有设置的情况下使用Dagger2生成的对象实例会更灵活。但是这样做,又会使得如果外部确实需要传空,但是dagger2生成的实例让变量非空,又会失去外部控制的意义。

实现原理:

DaggerCarComponent:

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

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

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

  @Override
  public BMW makeBmw() {
    return injectBMW(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() {
      return new DaggerCarComponent(injectWheel);
    }
  }
}

可以看到,@BindsInstance标注的方法injectWheel()注入的实例,在调用build()时会传给DaggerCarComponent,作为它的成员变量。最终在给BMW对象注入依赖时,直接使用了外部传入的这个实例。看起来,实现还是比较简单。