懒加载——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中有效。