某些场景下,@Inject构造函数的类实例化的数量或者@Provides方法调用后产生的实例数量需要做限制,同时又不需要保证在整个生命周期过程中,产生的对象都是同一个。在Android里面,这样会很有作用,因为Android的资源有限,内存分配需要很谨慎。
通过使用@Resuable,component可以缓存实例对象。@Resuable不像其他的scope,是跟单个的component绑定;相反,只有确实使用到了绑定关系的component才会缓存实例化对象。
如果在component中使用了一个有@Resuable绑定关系的module,但是只有一个子component实际上使用了这个绑定,那么只有这个子component会缓存这个绑定的对象。如果两个子component没有共享祖先,而是各自使用了这个绑定,那么它们会缓存各自的实例对象。如果一个component的祖先已经缓存过这个对象,那么子component会复用。
因为不能保证component只会调用一次绑定,所以使用@Resuable绑定可变对象,或者需要确保对象引用一致的场景下,是非常危险的。相反的,对一些不变的对象使用@Resuable是比较安全的,这些对象通常情况下你不关心他们创建了多少次。
@Reusable没有定义作用域,因此主要对提供方法进行修饰即可,而且它提供的复用,不是严格的同步单例,只是一个“尽量复用”逻辑。
将@Reusable使用在被@Inject标记构造函数的类上
@Reusable
public class BMWWheel implements IWheel {
@Inject
public BMWWheel() {
super();
}
@Override
public int size() {
return 100;
}
@Override
public int color() {
return 10;
}
}
module类:
@Module
public class WheelModel {
@Provides
public static IWheel provideBMWWheel(BMWWheel wheel) {
return wheel;
}
}
component类:
@Component(modules = WheelModel.class)
public interface CarComponent {
BMW makeBmw();
}
测试1:
public static void main(String[] args) {
CarComponent component = DaggerCarComponent.create();
for(int i =0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(component.makeBmw().wheel);
}
}).start();
}
}
结果:
> Task :CarMain.main()
com.hero.BMWWheel@5f021f87
com.hero.BMWWheel@13d5fcb8
com.hero.BMWWheel@733bfff1
com.hero.BMWWheel@4920a538
com.hero.BMWWheel@1a2de91d
com.hero.BMWWheel@68fcb38
com.hero.BMWWheel@551fca5e
com.hero.BMWWheel@60fe31fb
com.hero.BMWWheel@2eff815c
com.hero.BMWWheel@27ccf550
可以看到这种情况下,每次创建的BMWWheel对象是不一样的。
测试2:
public static void main(String[] args) {
CarComponent component = DaggerCarComponent.create();
for(int i =0;i<10;i++){
int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * finalI);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(component.makeBmw().wheel);
}
}).start();
}
}
结果:
> Task :CarMain.main()
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
com.hero.BMWWheel@29bd1204
可以看到每次创建的对象都是一样的。原因分析:
dagger2生成的DaggerCarComponent中定义了一个提供BMWWheel的Provider,而它的类型是SingleCheck的,这个SingleCheck的get()方法并没有保证同步,只是判断是否被创建过,那么在多线程场景下,就会出现多次创建。
DaggerCarComponent:
......
private IWheel getIWheel() {
return WheelModel_ProvideBMWWheelFactory.provideBMWWheel(bMWWheelProvider.get());
}
@SuppressWarnings("unchecked")
private void initialize() {
this.bMWWheelProvider = SingleCheck.provider(BMWWheel_Factory.create());
}
......
再看下SingleCheck的get()方法:
public T get() {
Object local = instance;
if (local == UNINITIALIZED) {
// provider is volatile and might become null after the check, so retrieve the provider first
Provider<T> providerReference = provider;
if (providerReference == null) {
// The provider was null, so the instance must already be set
local = instance;
} else {
local = providerReference.get();
instance = local;
// 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) local;
}
所以在多线程同时创建对象时就出现了每次得到的对象都不一样,所以@Reusable不能保证对象唯一。
注意:在module类中,如果是通过每次new方法来提供对象,那么@Reusable是无效的:
@Module
public class WheelModel {
@Provides
public static IWheel provideBMWWheel() {
return new BMWWheel();
}
}
同理,在Module类中,给provideXX()方法添加@Reusable注解的效果与上述用法类似。