如果要在构建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对象注入依赖时,直接使用了外部传入的这个实例。看起来,实现还是比较简单。