• The ultimate goal of this blog series is to build the MVP + Dagger2 framework
  • This blog series contains the following posts:
  1. Dagger series 1 — Prelude: Basic introduction to dependency injection
  2. Dagger 2 series (2) — Basic: @Inject, @Component
  3. Dagger: @Module & @Provides
  4. Dagger 2 series (4) — Foundation: @named & @Qualifier
  5. Dagger: @Scope & @singleton

What you will see in this article:

  1. @ScopeWhat is the
  2. @SingletonWhat is the
  3. @Scopeand@ComponentHow to work together.

Dagger2 does have a steep learning curve. I think the steep point is understanding the concept of dependency injection (INVERSION of Control), hence the Dagger2 series (1). Basic dependency injection, another is the understanding of the Scope, for this I also read a lot of blog, blog feelings after watching the most still is in the clouds and fogs, he was again after the study, ran aground, reciprocating process of learning, but also looked at some foreign blog, have a basic understanding about the concept of Scope.

1. @Scope

Let’s first take a look at froer_Mcs’ article about what Scope can bring us

  • In Dagger 2 scopes mechanism cares about keeping single instance of class as long as its scope exists. In practice it means that instances scoped in @ApplicationScope lives as long as Application object. @ActivityScope keeps references as long as Activity exists (for example we can share single instance of any class between all fragments hosted in this Activity).

  • In short-scopes give us “local singletons” which live as long as scope itself.

  • Annotated dependencies are single-instances but related to component lifecycle (not the whole application).

The translation

The Scope mechanism in Dagger2 guarantees that classes will remain singletons within Scope. In practice, this means that an instance object of a class in the scope of @ApplicationScope has a lifetime as long as an Application, and an instance of a class in the scope of @ActivityScope has a lifetime as long as the Activity. (Don’t assume that Dagger2 will implement the singleton effect of the corresponding class instance according to the literal meaning of the Scope annotation; implementing this effect requires concrete implementation.) In general, the Scope mechanism guarantees “local singletons” for the life of the Scope. Scope annotation dependencies guarantee singletons for the life of the Component. (That is, the singleton here is a singleton within the Component lifecycle; if the Component instance object is re-instantiated, the singleton effect is invalid.)

Through the above quotation and translation, I wonder if you have a new understanding of Scope. There is a concept repeatedly emphasized in the above article:

The Scope mechanism in Dagger2 ensures that classes hold singletons within the Component Scope of the Scope tag. (Tap on the blackboard, this is very important.)

2. @Singleton

To reiterate:

** The Scope mechanism in Dagger2 ensures that classes are kept singleton ** within the Component Scope of the Scope tag

If you understand that, it’s a bit of an epithet to look back at @Singleton. Not only the classes associated with the @Singleton annotation tag are singletons, but all the classes associated with the Scope tag are singletons. Only this singleton is conditional — instances produced within the Scope of the Component annotation tag are singletons.

In fact, Singleton under Scope mechanism has nothing to do with the literal meaning of @Singleton. I was misled by this wrong idea for a long time. You can replace @singleton with any word you want, such as @dog, @cat, or @xxx, as long as you ensure that the Component of the annotation tag is Singleton in the App process. And if implemented correctly (a method that is correctly labeled as @Provides in a class constructor or Module), its corresponding generated class instance is singleton.

@Singleton is implemented by default only because it lets you know that the instance of the class it flags is a Singleton by its literal meaning, which conforms to the Java naming convention.

3. sample code

This is all theory, so let’s test it with code.

  • A custom Scope
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface AnyOneScope {
}
Copy the code

In order to show that the last singleton has nothing to do with the Scope name, the name avoids confusing ApplicationScope, ActivityScope, etc., and uses AnyOneScope instead, but these names are actually irrelevant.

  • POJO — AppleBean
public class AppleBean {

    private String color;
    private int weight;

    public AppleBean() {
        Log.e("TAG"."AppleBean"); }}Copy the code
  • POJO — OrgranBean
public class OrgranBean {

    private String color;
    private int weight;

    public OrgranBean() {
        Log.e("TAG"."OrgranBean"); }}Copy the code
  • Module
@Module
public class FruitModule {

    @AnyOneScope
    @Provides
    AppleBean provideApple() {
        return new AppleBean();
    }

    @AnyOneScope
    @Provides
    OrgranBean provideOrgran() {
        returnnew OrgranBean(); }}Copy the code

This Module provides methods on AppleBean and OrgranBean instance objects, annotated with @anyonescope.

  • Component
@AnyOneScope @Component(modules = {FruitModule.class}) public interface FruitComponent { void inject(FuriteScopeActivity  mTestScopeActivity); }Copy the code
  • Target class (injected class)
public class FuriteScopeActivity extends AppCompatActivity {

    @Inject
    AppleBean mAppleBeanA;
    @Inject
    AppleBean mAppleBeanB;
    @Inject
    OrgranBean mOrgranBeanA;
    @Inject
    OrgranBean mOrgranBeanB;
    FruitComponent mFruitComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_scope); mFruitComponent = DaggerFruitComponent.builder().fruitModule(new FruitModule()).build(); mFruitComponent.inject(this); // Complete the injection."TAG"."mFruitComponent1:" + mFruitComponent.toString());
        Log.e("TAG"."mAppleBeanA:" + mAppleBeanA.toString());
        Log.e("TAG"."mAppleBeanB:" + mAppleBeanB.toString());
        Log.e("TAG"."mOrgranBeanA:" + mOrgranBeanA.toString());
        Log.e("TAG"."mOrgranBeanB:"+ mOrgranBeanB.toString()); }}Copy the code

As shown in the code, two instances of AppleBean and OrgranBean were called respectively after injection. According to our understanding of @Scope above, the class instance generated by the two classes is the same. Let’s run the code and check the log to verify.

The following logs are displayed:

E/TAG: mFruitComponent1:com.example.administrator.dagger2demo.practiceFifth.DaggerFruitComponent@7c6e469
    mAppleBeanA:com.example.administrator.dagger2demo.practiceFifth.AppleBean@b7d6eee
    mAppleBeanB:com.example.administrator.dagger2demo.practiceFifth.AppleBean@b7d6eee
    mOrgranBeanA:com.example.administrator.dagger2demo.practiceFifth.OrgranBean@648ef8f
    mOrgranBeanB:com.example.administrator.dagger2demo.practiceFifth.OrgranBean@648ef8f

Copy the code

MAppleBeanA, mAppleBeanB, mAppleBeanB, mAppleBeanB Two instances of OrgranBean — mOrgranBeanA, mOrgranBeanB, It is found that if the hash values of mAppleBeanA and mAppleBeanB are the same, it is the same object; if the hash values of mOrgranBeanA and mOrgranBeanB are the same, it is the same object, which verifies our understanding of @Scope — implementation singleton.

Also, to verify that singletons are scoped — within the scope of Component, add the following method to the FuriteScopeActivity:

public void jump(View view) { mFruitComponent = DaggerFruitComponent.builder().fruitModule(new FruitModule()).build(); mFruitComponent.inject(this); // Complete the injection."TAG"."mFruitComponent2:" + mFruitComponent.toString());
        Log.e("TAG"."mAppleBeanA:" + mAppleBeanA.toString());
        Log.e("TAG"."mAppleBeanB:" + mAppleBeanB.toString());
        Log.e("TAG"."mOrgranBeanA:" + mOrgranBeanA.toString());
        Log.e("TAG"."mOrgranBeanB:" + mOrgranBeanB.toString());
    }
Copy the code

Rerun the program and observe the printed log:

  • Log information triggered after running the program:
09-21 14:50:54. 903, 14184-14184 / com. Example. Administrator. Dagger2demo E/TAG: AppleBean OrgranBean mFruitComponent1:com.example.administrator.dagger2demo.practiceFifth.DaggerFruitComponent@7c6e469 mAppleBeanA:com.example.administrator.dagger2demo.practiceFifth.AppleBean@b7d6eee mAppleBeanB:com.example.administrator.dagger2demo.practiceFifth.AppleBean@b7d6eee MOrgranBeanA:com.example.administrator.dagger2demo.practiceFifth.Org ranBean @ 648 ef8f 09-21 14:50:54. 904 14184-14184/com.example.administrator.dagger2demo E/TAG: mOrgranBeanB:com.example.administrator.dagger2demo.practiceFifth.OrgranBean@648ef8fCopy the code

The generated object corresponds to the hash value as follows:

  • DaggerFruitComponent –> 7c6e469
  • AppleBean –> b7d6eee
  • OrgranBean –> 648ef8f
  • The following log information is displayed after the jump() method is triggered:
09-21 14:53:37. 624, 14184-14184 / com. Example. Administrator. Dagger2demo E/TAG: AppleBean OrgranBean mFruitComponent2:com.example.administrator.dagger2demo.practiceFifth.DaggerFruitComponent@8196f9e mAppleBeanA:com.example.administrator.dagger2demo.practiceFifth.AppleBean@50ada7f mAppleBeanB:com.example.administrator.dagger2demo.practiceFifth.AppleBean@50ada7f mOrgranBeanA:com.example.administrator.dagger2demo.practiceFifth.OrgranBean@16bea4c mOrgranBeanB:com.example.administrator.dagger2demo.practiceFifth.OrgranBean@16bea4cCopy the code

The generated object corresponds to the hash value as follows:

  • FruitComponent –> 8196f9e
  • AppleBean –> 50ada7f
  • OrgranBean –> 16bea4c

Obviously AppleBean and OrgranBean have regenerated new objects. Isn’t that a singleton? Is the above conclusion wrong? FruitComponent generates new objects, so classes in its scope regenerate new instances. Proves that instances produced within the Scope of the Component annotation tag are singletons.

4. To summarize

So far, the understanding of Scope in Dagger2 is just as shown above. I think the content is easy to understand and simple, so it won’t add to your doubts. I hope this learning record can help all students who see it.

You can see GitHub–Dagger2Demo here


The resources

Dependency injection with Dagger 2 – the API

Dependency injection with Dagger 2 – Custom scopes