概述:在Dagger2中,@Singleton注解可以保证被注解的对象全局都是单例。本篇主要分析为什么这个注解会有这种效果。
首先@Singleton注解需要在两处添加:
第一处是在创建实例的地方添加
@Module
public class MainModule {
@Provides
@Singleton
static Student provideStudent(){
return new Student();
}
@Provides
static Teacher provideTeacher(){
return new Teacher();
}
}
之所以写了一个provideTeacher是为了待会做对比。
第二处需要在Component添加:
@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
添加完之后编译下,我们来看看生成的类文件有什么变化。
仔细对比会发现,主要的变化在DaggerMainComponent类里面:
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectStudent(instance, provideStudentProvider.get());
MainActivity_MembersInjector.injectStudent1(instance, provideStudentProvider.get());
MainActivity_MembersInjector.injectTeacher(
instance, MainModule_ProvideTeacherFactory.proxyProvideTeacher());
MainActivity_MembersInjector.injectTeacher1(
instance, MainModule_ProvideTeacherFactory.proxyProvideTeacher());
return instance;
}
Student类添加了@Singleton注解,而Teacher类没有。不同之处在于,Student实例对象是通过provideStudentProvider.get()获得的。而Teacher实例直接通过编译出来的工厂类创建。从这里其实可以分析下,这个provideStudentProvider一定是对新生成的对象做了单例处理。
果不其然:
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideStudentProvider = DoubleCheck.provider(MainModule_ProvideStudentFactory.create());
}
这个provideStudentProvider ,是通过DoubleCheck对Student的工厂类进行了包装之后得到的,那么它调用的get方法其实是DoubleCheck里面的get方法,继续点击去看一下:
//这里对返回的对象做了单例的处理
@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;
}
由此可以得出结论,添加了@Singleton注解之后,会有DoubleCheck这个类去做处理。这样就保证了每次获取的对象的唯一性。