The use of Dagger2 basics

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


    This article mainly talks about the application foundation of Dagger.

basic annotations

    Dagger2 is an annotation framework that uses annotations to generate fixed code templates at compile time to complete object creation and target object dependencies.

    Due to space limitations, let's talk about 4 annotations first, as long as we have these 4 annotations, we can complete most of the application scenarios.

    @Inject : Translated into injection, this annotation is in the javax package, not a unique annotation of Dagger. It acts on the constructor and fields in Dagger, and in the constructor, it will parse and generate a factory template object of a class, indicating that the An instance of a class, used in a field, means creating an object to get an object instance.

    Classes provided by @Inject have the following limitations:

      1. Because the interface has no construction method and cannot be used, the idea of ​​not being able to use the interface programming in the program is very scary.

      2. When using third-party objects, we cannot directly modify the source code of other objects, so it is unrealistic to use the construction method.

      3. There are also some special classes, which are developed using the builder mode to configure and generate objects, and the construction method itself is prohibited.

    @Component : Translated into a component, the role of @Component in Dagger is to associate, for example, we need a Goods commodity object in our Activity, but if we only use @Inject, it will not work, because when @Inject acts in the construction method of Goods, It just provides a factory class, and the field acting on Activity only tells the interpreter that Activity needs this object but does not perform the associated operation. @Component will generate a class for the program that provides the pipeline associated with the Activity and the Goods factory class. No error will be reported when there is no Component editing, but the object must be null.

    @Module : Modules are used in classes. They are unique annotations added by Dagger to solve the limitations of @Inject. They are also created to generate objects. They are used in conjunction with @Provides and are used to distinguish modules, such as networks. , db, Sp, etc. all have their own classes that need to be generated. We can always put them in a class. It has a one-to-many relationship with @Provides. @Provides cannot be separated from his implementation, otherwise an error will be reported.

    @Provides : Provides classes, which can only be used in methods, not in methods of classes not annotated with @Module, otherwise an error will be reported: Error:(18, 18) Error: @Provides methods can only be present within a @Module or @ProducerModule, which acts like @Inject to generate factory classes.


    The basic concepts have been said, but it is in the clouds, and we need some examples to help us to understand Dagger in depth.

Generate a simple object @Inject 

    Now I have a requirement. I need a Goods product object without any data. When we haven't learned Dagger2, we will directly create a new one. With the Dagger2 weapon, we will use another method to create a new one. operate.

    Create a class with a parameterless constructor and decorate the constructor with @Inject:

    @Inject
    public Goods(){

    }

    Then when we need to use it in Activity, we just need to add the following code:

    

@Inject
Goods mGoods;

  

 Next we create a component without modules:

@Component
public interface MainActivityComponet {

    void inject(MainActivity activity);
}

 Next, let's make project for the project. After compiling, you can view build->generated->source->apt

->debug(release)->project package->find the generated file, if it is not generated, check whether an error is reported, if no error is reported, check whether apt is added to the configuration, here we mainly focus on the class generated by Component, with Dagger+xxx( Component), here my project generates the DaggerMainActivityComponet class, which is what we use to associate Activity and Goods. The compilation diagram is as follows:


The simplest is to generate three classes, let's talk about their functions:

The role of XX_Factory is the factory class of XX class

Dagger+xx is generated based on the Component component, and its role is to associate the project class with the XXX_MembersInjector class.

The class XXX_MembersInjector is generated by the field @Inject in Activity

Let me briefly talk about it here. Of course, only by actually looking at the source code can we learn Dagger2 better, and the source code interpretation will be updated later.

The last step is to use Dagger+XX in the Activity to tell the framework that the class that needs to use the object is:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerMainActivityComponet
                .builder()
                .build()
                .inject(this);

        Log.d(TAG,mGoods.toString());
    }
Send after running, Log can print out the reference address of the Goods object, indicating that Goods has created a new object

generate an object with dependencies

Let's talk about the requirements first:

    For example, assuming that there is a one-to-one relationship between orders and products, I need an order object without data, how do I do it?

    Let's create an order class first:

    

public class Order {

    @Inject
    public Order(Goods mGoods) {
        this.mGoods = mGoods;
    }

    private Goods mGoods;
}

Use objects in Activity:


This order class just adds an object field of the product, the previous code does not change, and then compiles.


Compared with the previously compiled pictures, without considering the internal implementation, only an Order_Factory is added, and the print Log is as follows:


Seeing that the Log object is generated, we did nothing but build an order class, generate an Order object for the order, and automatically assemble the objects that need to be dependent, just like there is an object pool, Order tells the object pool, I I need a Goods class, you can give me one, and the object pool is responsible for generating an object for the Order class.

Generate a third-party object @Module and @Provides

    According to the previous two annotations, we can actually complete the creation of ordinary objects, but when we need to create a self-written Sdk object or a third-party object, we can't change the previous code, so @Module And @Provides came into being, let's create a Gson object:

    First of all, we need to clarify what object we need to create. For example, we need a Gson class. Usually we need a Gson object, that is, direct Gson mGson=new Gson(), without any dependencies.

    In the second step, we create a Module class, such as XXX_Module. There is no requirement for the class name here, but for better distinction, it is recommended that you name it like this, and then write the code as follows:

    

@Module
public class ObjectModule {

  @Provides
  public Gson provideGson () {
      return new Gson();
  }

In the ObjectModule class, use @Provdes to decorate a method to generate a new Gson.

    The third step, we need to tell the component Component, we need a Module, what is the name of this Module, MainActivityComponet is modified as follows:

    

@Component(modules = ObjectModule.class)
public interface MainActivityComponet {

    void inject(MainActivity activity);
}

It is to add the assignment of modules in the @Component tag, and the Activity is modified as follows:

@Inject
Gson mGson;
DaggerMainActivityComponet
                .builder()
                .objectModule(new ObjectModule())
                .build()
                .inject(this);

There is an extra sentence objectModule(new ObjectModule()), which is to inject the ObjectModule object for the component, and the operation is completed. It should be noted here that each required Module in the component is injected into the component.


common problem:

1. The @Inject modified object cannot be private, otherwise an error will be reported: Error: (13, 20) Error: Dagger does not support injection into private fields

2. The class does not use the @Module annotation but the method uses the @Provides annotation to report an error: Error:(18, 18) Error: @Provides methods can only be present within a @Module or @ProducerModule

3. When we set the @Inject field in the target class and @Component, @Module, the program cannot scan the generated object:

Error:(21, 10) 错误: com.lyc.love.dagger2demo.bean.Goods cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
com.lyc.love.dagger2demo.bean.Goods is injected at
com.lyc.love.dagger2demo.MainActivity.mGoods3
com.lyc.love.dagger2demo.MainActivity is injected at

com.lyc.love.dagger2demo.dagger2.component.MainActivityComponet.inject(activity)

This kind of error, let us check that @Module provides @Provides annotation.

4. When using the incoming Module of Module, the method becomes the abandoned @deprecated flag, and is described as This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https ://google.github.io/dagger/unused-modules. This is because no objects in Module are used in Activity, so when compiling, the framework is marked as not required to be used. Just recompile it.

5. Error:(15, 1) Error: com.chipsea.yilianintelligence.mydevice.dagger.component.MyDeviceComponent (unscoped) may not reference scoped bindings because Mudle sets Scope, but Compoenent does not.

Guess you like

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