Dagger2——Lazy injections,Provider injections

834 阅读3分钟

懒加载——Lazy

​ 有时候,某些对象需要被懒加载,不用在一开始就创建出来,这样可以减少内存开销以及初始化时间。那么,对于任何的类型T,都可以创建一个Lazy类型的对象,它会在第一次被调用get()方法时返回一个T类型的实例。如果T是一个单例,那么在范围内,所有的注入返回的都是同一个Lazy实例。否则,每次注入都返回的是各自的Lazy实例。

BMWWheel:

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

WheelModule:

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

CarComponent:

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

测试:

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

结果可以看到每次打印的wheel是同一个对象。

实现原理:

DaggerCarComponent:

public final class DaggerCarComponent implements CarComponent {
  private DaggerCarComponent() {

  }

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

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

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

  private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectWheel(instance, DoubleCheck.lazy((Provider) BMWWheel_Factory.create()));
    return instance;
  }

  public static final class Builder {
    private Builder() {
    }

    public CarComponent build() {
      return new DaggerCarComponent();
    }
  }
}

​ 可以看到,DaggerCarComponent注入到BMW对象实例中的wheel属性是一个DoubleCheck类型。而DoubleCheck内部实现了get()方法,使用synchronized保证了每次获取到的都是同一个对象。

  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          result = provider.get();
          instance = reentrantCheck(instance, result);
          /* Null out the reference to the provider. We are never going to need it again, so we
           * can make it eligible for GC. */
          provider = null;
        }
      }
    }
    return (T) result;
  }

​ 其中的reentrantCheck()方法有些费解。。

​ 另一种测试:

public class CarMain {
    public static void main(String[] args) {
        CarComponent component = DaggerCarComponent.create();
        System.out.println(component.makeBmw().wheel);
        System.out.println(component.makeBmw().wheel);
        System.out.println(component.makeBmw().wheel);
    }
}

​ 很明显,每次打印的wheel对象都是不一样的,说明Lazy注入只跟Lazy对象有关,如果Lazy对象实例不一样,切注入的类型T不是单例的,那么每次返回的都是不同的对象。

Provider注入

​ 如果想每次获取到的T类型的实例都不一样,那么可以使用Provider注入,即Provider。这样每次调用get()方法时都会重新调用Module里面的绑定逻辑。如果每次Module中提供的都是一个新的对象实例,那么每次调用Provider的get()方法都是同一个实例。

BMWWheel同上

BMW:

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

    @Inject
    Provider<IWheel> wheel;
}

区别就是此处注入的是Provider,而不是IWheel,或者Lazy

BMWModule和CarComponent同上。

测试:

public class CarMain {
    public static void main(String[] args) {
        CarComponent component = DaggerCarComponent.create();

        BMW bmw = component.makeBmw();
        System.out.println(bmw.wheel.get());
        System.out.println(bmw.wheel.get());
        System.out.println(bmw.wheel.get());
    }
}

明显的,每次打印的IWheel实例都不一样。

实现原理,可以想到主要逻辑在DaggerCarComponent中:

public final class DaggerCarComponent implements CarComponent {
  private DaggerCarComponent() {

  }
    //...
  private BMW injectBMW(BMW instance) {
    BMW_MembersInjector.injectWheel(instance, WheelModel_ProvideBMWWheelFactory.create());
    return instance;
  }
	//...
}

​ 可以看到,注入到BMW对象中的是一个工厂类的实例-WheelModel_ProvideBMWWheelFactory:

public final class WheelModel_ProvideBMWWheelFactory implements Factory<IWheel> {
  @Override
  public IWheel get() {
    return provideBMWWheel();
  }

  public static WheelModel_ProvideBMWWheelFactory create() {
    return InstanceHolder.INSTANCE;
  }

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

  private static final class InstanceHolder {
    private static final WheelModel_ProvideBMWWheelFactory INSTANCE = new WheelModel_ProvideBMWWheelFactory();
  }
}

​ 可以看到,这个WheelModel_ProvideBMWWheelFactory工厂类是一个静态内部类实现的单例。也就是说,不同的BMW实例中的Provider类型的wheel变量其实引用了同一个单例。

​ 它实现了get()方法,内部会再调用provideBMWWheel()方法,而这个方法内部又会调用WheelModel.provideBMWWheel()方法,所以就验证了之前的说法,每次调用Provider的get()方法都会重新调用@Module类中的提供依赖的方法。因此,也可以想到Provider不能保证每次获取到的T类型的实例都是不一样的,这取决于@Module中的实现,以下这种@Singleton的方式就会一样。

BMW:(给BMWWheel增加@Singleton)

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

WheelModel:

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

并给CarComponent增加@Singleton

那么显然,每次调用WheelModel的provideBMWWheel()其实得到的都是同一个BMWWheel实例,这是因为@Singleton在Component中有效。