看简书的两篇文章的时候关于Dagger2中的@Singleton的理解和Android:dagger2让你爱不释手-重点概念讲解、融合篇,里面讲解了关于Scope的作用和SingleTon为什么能实现单例。在上一篇文章中也有讲Scope的作用。
这里再说一下,Scope是用于组织Component。在Dagger2中, Scope机制关注的是保持单例和Scope存在周期一致。 实际上,它意味着@ApplicationScope标识的实例与Application对象一样长。@ActivityScope标识的实例与Activity对象一样长(例如,我们可以在此Activity中包含的所有Fragment*享任何类的单例)。就是说Scope给我们塑造了一个和Scope注解生命周期完全一样的“单例”。
第一个问题:那到底是如何形成的单例呢?
第二个问题:Activity和Fragment中同时注入了一个Presenter,那这两个变量是不是同一个变量呢?
看下两段代码
@Module public abstract class AllActivityModule { @ActivityScoped @ContributesAndroidInjector(modules = TasksFragmentModule.class) abstract TasksActivity contributeTasksActivityInjector(); }
@Module public abstract class TasksModule { @FragmentScoped @ContributesAndroidInjector abstract TasksFragment tasksFragment(); @ActivityScoped @Binds abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter); }
这是生成的TasksPresenter_Factory的代码。
@Generated( value = "dagger.internal.codegen.ComponentProcessor", comments = "https://google.github.io/dagger" ) public final class TasksPresenter_Factory implements Factory<TasksPresenter> { private static final TasksPresenter_Factory INSTANCE = new TasksPresenter_Factory(); @Override public TasksPresenter get() { return new TasksPresenter(); } public static Factory<TasksPresenter> create() { return INSTANCE; } }
可以看到在这个类继承了Factory接口,然后实现了get()方法,然后Find Usage会发现在TaskActivity的injectMembers方法和TaskFragment的injectMembers方法中用到了(注意,这儿的用到非常重要!!!)
@Override public void injectMembers(TasksActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } com.example.todoapp.base.BaseActivity_MembersInjector.injectDispatchingFragmentInjector( instance, dispatchingFragmentInjectorProvider); instance.tasksPresenter = tasksPresenterProvider.get(); }
以上的情况属于没有给TasksPresenter标示Scope的情况,下面来看另外一种情况
@ActivityScoped public class TasksPresenter implements TasksContract.Presenter { ... }
使用ActivityScope注解标示,这时候按照上面的思路继续看。DaggerTodoApplicationComponent中调用了TasksActivity_MembersInjector.create()方法传递了Provider<TasksPresenter>类型的参数,不是原先的TasksPresenter_Factory.create()了,而是tasksPresenterProvider,查找会发现下面的代码
this.tasksPresenterProvider = DoubleCheck.provider(TasksPresenter_Factory.create());
DoubleCheck?这是个啥玩意?看下这个类中的get方法
@SuppressWarnings("unchecked") // cast only happens when result comes from the provider @Override public T get() { Object result = instance; if (result == UNINITIALIZED) { synchronized (this) { result = instance; if (result == UNINITIALIZED) { result = provider.get(); /* Get the current instance and test to see if the call to provider.get() has resulted * in a recursive call. If it returns the same instance, we'll allow it, but if the * instances differ, throw. */ Object currentInstance = instance; if (currentInstance != UNINITIALIZED && currentInstance != result) { throw new IllegalStateException("Scoped provider was invoked recursively returning " + "different results: " + currentInstance + " & " + result + ". This is likely " + "due to a circular dependency."); } 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; }
这不就是单例吗!也就是说这种情况下injectMembers方法中tasksPresenterProvider.get()调用的是DoubleCheck的get方法而不是TasksPresenter_Factory的get方法了,因而实现了单例。还有一个问题,为什么这个单例的生命周期和Activity的生命周期一致呢?它咋不和Fragment生命周期一致?我在TaskFragment中使用的Presenter的对象和在TaskActivity中使用的Presenter是同一个对象啊!(不信的话可以试一下 :) )
tasksPresenterProvider这个成员变量是谁的成员变量呢?是TasksActivitySubcomponentImpl这个类的,这个类继承了TasksActivitySubcomponent,而我们知道Component和Activity的生命周期是一致的。这也就是为什么TasksPresenter和TasksActivity生命周期一致类。
这儿正好再说一下上一篇文章中提到的Scope的使用的第三条
更好的管理Component与Module之间的匹配关系,编译器会检查 Component管理的Modules,若发现标注Component的自定义Scope注解与Modules中的标注创建类实例方法的注解不一样,就会报错。(Modules中的标注Scope可以不写,但是不能不同!)
代码在:https://github.com/fanturbo/TodoApp
参考:
https://*.com/questions/29923376/dagger2-custom-scopes-how-do-custom-scopes-activityscope-actually-work
https://*.com/questions/29528599/scopes-in-dagger-2/29619594#29619594