dagger2——@Resuable

·  阅读 546

​ 某些场景下,@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注解的效果与上述用法类似。

分类:
Android
标签: