Dagger2 Advanced - Scope Control (Scope and Singleton)

foreword

        Introduction and configuration of Dagger2

        The use of Dagger2 basics

        Dagger2 Advanced - Compiling and Generating Source Code Interpretation

        Dagger2 Advanced - Scope Control (Scope and Singleton)

        Dagger2 Advanced-Scope Source Code Exploration

        Project source code portal

Annotation Explanation

    @Singleton : It is determined that the generated class is a single column, that is, the active time of the object is determined, which belongs to a global singleton. It is used in the @Provides method and should also be configured in @Component.

   @Scope : Scope, the application in Dagger2 is to determine the life cycle of the object, that is, to determine the scope of the object's survival. is a local variable annotation whose active scope is within the @Component decorated by the annotation.

Create a global singleton with Singleton

How do we do it when our needs become a single-column object?

    Let's first take a look at what happens when we do not do any scoped range operations:


It can be seen that the address references of the two Goods are inconsistent, indicating that the creation of the object is not a single column by default. Let's modify the code. The commodity class Goods is provided by @Module and modified with @Singleton. After @Singleton modifies the method provided by @Provides , and also modify the Component:


After running, the result is as follows:


We can see that the object implements a singleton, and the @Singleton annotation generates a singleton object, however, is this really the case?

Let's build a second Activity, and then create a new component, TwoComponent:



run. . . Expect  


However, oh my god, isn't it a good singleton, why the reference address has changed. Let's take a look at @Singleton's source code:

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

In the source code, we know that @Singleton uses the @Scopen annotation, and its principle is the same as @Scope, so it is not a complete singleton, and its determined scope is only limited to its components? Later, we will analyze why this happens through the source code, and then we will start from scratch to implement a singleton object for the whole application:

Build an APP-level Module and Component:

@Module
public class AppModule {

    @Singleton
    @Provides
    Goods providesGoods(){
        return new Goods();
    }
}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication myApplication);
    
    //Tell the dependent Component that I gave you this class. than essential.
    Goods getGoods();
}

Then we modify the components of the Activity below:

@ActivityScope
@Component(modules = ObjectModule.class,dependencies = AppComponent.class)
public interface MainActivityComponet {

    void inject(MainActivity activity);
}
@ActivityScope
@Component(modules = ObjectModule.class,dependencies = AppComponent.class)
public interface TwoComponent {
    void inject(TwoActivity twoActivity);
}

Both use dependencies to depend on a parent component, and set an @ActivityScope scope annotation. If you do not set the annotation, an error will be reported.

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}


Because we need to depend on components, in MainActivity and TwoActivity we have to tell the framework what components we depend on



Compilation result:



A proper global singleton is completed.

Create a local singleton with @Scope

I think I don't need to post code for this. . In fact, @Singleton is also a @Scope annotation, but the framework has set one for us, so by changing @Singleton to @ActivityScope, we will not build a partial singleton under the wrong understanding. As for why the scope is based on the scope of the component, we can understand that each component is an object pool, and @Scope just keeps it unique in a single object pool, and the specific source code analysis will be updated later.


common problem:

1. When the method @Provides determines Scoped, the component Component does not set Scoped: Error: (17, 1) Error: com.lyc.love.dagger2demo.dagger2.component.MainActivityComponet (unscoped) may not reference scoped bindings: @Singleton @Providescom.google.gson.Gson com.lyc.love.dagger2demo.dagger2.module.ObjectModule.provideGson()

2. You need to provide a @Scope for components that depend on @Singleton decoration: Error:(17, 1) Error: This @Singleton component cannot depend on scoped components:

@Singleton com.lyc.love.dagger2demo.dagger2.component.AppComponent

3.Error:(18, 10) 错误: com.lyc.love.dagger2demo.bean.Goods cannot be provided without an @Inject constructor or 

This error has the following reasons:

    @1. If it is a class provided by a dependent Component, query whether the Component's Module is decorated with @Provided.

    @2. If the class provided by the dependent Component does not exist in the above situation, check whether a method is provided externally in the Component. for example:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(MyApplication myApplication);

    //Tell the dependent Component that I gave you this class. than essential.
    Goods getGoods();
}

    @3. Check the Module in the required class. Whether to modify @Provided




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325529920&siteId=291194637