Dagger2: How to use Scope and why Singleton can implement singletons The function of Scope was also mentioned in the last article.

Again, Scope is used to organize components. In Dagger2, the Scope mechanism is concerned with keeping singleton and Scope existence cycles consistent. In practice, it means that the instance identified by @ApplicationScope is as long as the Application object. An instance of the @ActivityScope identifier is as long as an Activity object (for example, we can share a singleton of any class among all fragments contained in this Activity). That is, Scope gives us a “singleton” that has exactly the same lifecycle as a Scope annotation. First question: how exactly does that form a singleton?

A Presenter is injected into both Activity and Fragment. Are the two variables the same?

Let’s look at two pieces of code

@Module
public abstract class AllActivityModule {
    @ActivityScoped
    @ContributesAndroidInjector(modules = TasksFragmentModule.class)
    abstract TasksActivity contributeTasksActivityInjector();
}Copy the code


@Module
public abstract class TasksModule {

    @FragmentScoped
    @ContributesAndroidInjector
    abstract TasksFragment tasksFragment();

    @ActivityScoped
    @Binds
    abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter);
}Copy the code

This is the generated TasksPresenter_Factory code.


@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; }}Copy the code

You can see that this class inherits the Factory interface and implements the get() method. Find Usage is used in injectMembers of TaskActivity and injectMembers of TaskFragment. The usage here is very important!!


 @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();
  }Copy the code

DaggerTodoApplicationComponent invoke the TasksActivity_MembersInjector. The create () method is passed the Provider < TasksPresenter > parameter of type, Namely TasksPresenter_Factory. The create ()

This is the case where the TasksPresenter is not given a Scope. Let’s look at another case


@ActivityScoped
public class TasksPresenter implements TasksContract.Presenter {
...
}Copy the code

Use the ActivityScope annotation and continue along the same lines. DaggerTodoApplicationComponent invoke the TasksActivity_MembersInjector. The create () method is passed the Provider < TasksPresenter > parameter of type, Instead of the original taskspresenter_factory.create (), the tasksPresenterProvider will look for the following code


this.tasksPresenterProvider = DoubleCheck.provider(TasksPresenter_Factory.create());Copy the code

DoubleCheck? What the hell is this? Take a look at the get method in this class

@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; }Copy the code

This is a singleton! That is to say, this kind of circumstance injectMembers method tasksPresenterProvider. The get () call is DoubleCheck the get method instead of TasksPresenter_Factory the get method, thus implementing the singleton. One more question, why is the life cycle of this singleton the same as the life cycle of the Activity? Why isn’t it consistent with the Fragment life cycle? The Presenter object I use in TaskFragment is the same object as the Presenter object I use in TaskActivity. (Try it if you don’t believe me.)

Whose member variable is tasksPresenterProvider? Is TasksActivitySubcomponentImpl of this class, this class inherits the TasksActivitySubcomponent, and we know that is consistent with the Component and the Activity of the life cycle. This is why TasksPresenter and TasksActivity have the same life cycle class.

Here is the third article about the use of Scope mentioned in the last article

To better manage the relationship between Components and Modules, the compiler checks component-managed Modules and raises an error if a custom Scope annotation to Component is not the same as an annotation to create class instance methods in Modules. (The annotation Scope in Modules can be left out, but not different!)

The code is: github.com/fanturbo/To… Reference: stackoverflow.com/questions/2… Stackoverflow.com/questions/2…