Dagger2关于Scope的理解

时间:2022-05-01 21:01:37

看简书的两篇文章的时候关于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();
  }
这个方法的参数就是TaskAtivity类型!获取到的TaskPresenter赋值给了TaskActivity对象instance的成员变量tasksPresenter。这就解释了为什么Presenter的生命周期和Activity一致了,因为成员变量的生命周期肯定和类的生命周期一致啊!(TasksFragment_MembersInjector和TasksActivity_MembersInjector的获取思路一样,所以下面只从TasksActivity_MembersInjector这个类来理思路)
tasksPresenterProvider.get()这一行获取类TaskPresenter对象,那tasksPresenterProvider是如何来的呢?
TasksActivity_MembersInjector的构造方法的第二个参数赋值给了tasksPresenterProvider。而在 DaggerTodoApplicationComponent中调用了TasksActivity_MembersInjector.create()方法传递了Provider<TasksPresenter>类型的参数,即TasksPresenter_Factory.create(),TasksPresenter_Factory的一个单例。
DaggerTodoApplicationComponent到inject方法中,TasksActivity_MembersInjector的一个对象tasksActivityMembersInjector调用了injectMembers完成了TaskActivity注入TaskPresenter的这个操作。

以上的情况属于没有给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