Android popular open source tool (1) -Dagger2 entry (personally I believe the best new entry Dagger2 article)

Introduction

Dagger 2 is a dependency injection framework, it can be generated automatically at compile time some code that can help instance corresponding initialization. 
To give a concrete example, a container which is filled with apple, under no circumstances Dagger2 we should write:

public class Container{
    Fruit f=new Apple(color,size);
    ...
}

The above examples are faced with a problem, Container dependent on the Apple achieved if one day need to be modified for the Apple Banana, then you have to change Container code. Is there a way you can not change Container it? 
You can use Dagger2, we can change the code

public class Container{
    @Inject
    Fruit f;
    ...
}

In this way, Container member variables are automatically initialized to the example of Apple, Container do not care what Fruit achieve the specific use, they do not care about in the end how much of what color apples. If one day should replace apples bananas, Container code is completely without changes. In a sense, Dagger2 is a tool to help you write factory code. Of course Dagger2 more powerful than the factory model.

structure

Dagger2 To achieve a complete dependency injection, there are three essential elements, Module, Component, Container. 

ä¸èå³ç³»
1, Container that can be injected into the container, concrete examples corresponding to the above Container, Container element has to be initialized. It needs to be initialized elements must be marked @Inject, the element will only be marked with @Inject is automatically initialized. In general marker @Inject Dagger2 constructor and member variables.
2, Module can be said is dependent on raw materials manufacturing plant, to achieve all that needs to be injected elements are produced from the Module.
3, may be injected with the container Container, it has also been provided Module dependent objects. We must rely on the object poured into the container, this process is performed by Component. Component Object Module will rely generated automatically injected into the Container.


Simple example

Configuration

The project added build.gradle

 dependencies {
     ... // 其他classpath
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //添加apt命令
 }

Add module of build.gradle

// 添加其他插件
apply plugin: 'com.neenbedankt.android-apt'//添加apt命令

dependencies {
    apt 'com.google.dagger:dagger-compiler:2.0.2' //指定注解处理器
    compile 'com.google.dagger:dagger:2.0.2'  //dagger公用api
    provided 'org.glassfish:javax.annotation:10.0-b28'  //添加android缺失的部分javax注解
}

achieve


Realize Module

 Module is actually a dependent manufacturing plant. We just need to add a method for manufacturing-dependent, and examples vessel Apple continues to achieve above.

@Module //1  注明本类属于Module
public class FruitModule{
    @Provides  //2 注明该方法是用来提供依赖对象的特殊方法
    public Fruit provideFruit(){
        return new Apple(Color.RED,Size.BIG);
    }
}

(1) was added annotations indicate this category belongs @Module Module 
(2) was added annotation @Provides method is used to provide an indication that the object is dependent on the particular method of 
a Module must have a complete and @Provides annotation @Module 


Implement Component 


Component Module is generated to a Container Examples of injection of the injector. Let's write a fruit Injector:

@Component(modules={FruitModule.class}) //3 指明Component在哪些Module中查找依赖
public interface FruitComponent{    //4 接口,自动生成实现
    void inject(Container container);   //5  注入方法,在Container中调用
}

(3) the use of modules @Component Module used set points. 
(4) All Component interfaces must be defined in a form. Component Dagger2 frame automatically generated implementation class corresponding to the class name is Dagger ×××××, in this example corresponds to the implementation class is DaggerFruitComponent 
injection process (5) was added, inject generally used as the method name, parameters corresponding Container

Achieve Container 

Container may be injected into the vessel is dependency. To achieve the following specific

public Container{
     @Inject   //6 添加@Inject,标记f可以被注入
     Fruit f;
     public void init(){
         DaggerFruitComponent.create().inject(this); //7 使用FruitComponent的实现类注入
     }
 }

Container in addition to the code (6) flag f need to be injected, but also need the code (7) implementation class will call Component Module objects generated injected into f.

This, when calling the Container init () method, the f Contianer automatically initialized to Apple's object implementation class. 
If you later want to change the Fruit of the implementation class, just in @Component the modules can be directed to different Module. The Container code completely without changes. Because Container no longer dependent on Apple realized.

expand

Although Dagger2 look easy, but in fact there are all kinds of details worth noting.

Method add input parameters @Provides

Module in @Provides method may input parameters, the parameters provided by other methods @Provides Module set, or automatically call the constructor 
The following are examples of other methods provided @Provides

@Module
public class FruitModule{
    //8输入参数自动使用到provideFruit()的返回值Color.RED
    @Provides
    public Fruit provideFruit(Color color){         
        return new Apple(color,Size.BIG);
    }
    @Provides
    pulic Color provideFruit(){
        return Color.RED;
    }
}

If no @Provides constructor method for providing a corresponding object parameters, automatically generating a call with the corresponding object parameters @Inject

@Module
public class FruitModule{
    @Provides
    public Fruit provideFruit(FruitInfo info){//自动查找到FruitInfo中带@Inject的无参构造器并生成实例传入参数info
        return new Apple(info);
    }
}
public class FruitInfo{
    Color mColor;
    Size mSize;
    @Inject
    FruitInfo(){
        mColor=Color.RED;
        mSize=Size.BIG;
    }
}

Add Multiple Module


Component Module may comprise a plurality, of such time-dependent Component acquired from the plurality of acquired automatically finds Module, the method can not be duplicated between Module. There are two ways to add a plurality of Module A is a comment @Component (modules = {××××, ×××}) Component added in a plurality of modules, the following

@Component(modules={ModuleA.class,ModuleB.class,ModuleC.class}) //添加多个Module
public interface FruitComponent{
    ...
}

Another way to add a plurality Module Module may be used in @Module (includes = {××××, ×××}), as follows

@Module(includes={ModuleA.class,ModuleB.class,ModuleC.class})
public class FruitModule{
    ...
}
@Component(modules={FruitModule.class}) //添加多个Module
public interface FruitComponent{
    ...
}

This includes Module using the method generally used to build higher-level Module when using.

Creating Module instance

Simple example above, when the call DaggerFruitComponent.create () is essentially equivalent to DaggerFruitComponent.builder (). Build (). As can be seen, DaggerFruitComponent by using a configuration mode. During construction, the use of non-parametric Module instance generated default constructor. Module If you need to pass a specific instance, you can use

DaggerFruitComponent.builder()
.moduleA(new ModuleA()) //指定Module实例
.moduleB(new ModuleB())
.build()

Only if Module argument constructor must explicitly incoming Module instances.

Return the same type distinguishing method @Provides

When required injection Fruit, Dagger2 Module will find in the return type of Fruit method, i.e., Dagger2 find the corresponding return type is dependent on the method according to Provide. However, when the need to rely on two different Container Fruit, you will need to write two @Provides method, and that the two methods are @Provides Fruit return type, the return value by discriminating practices will not work. This requires the use @Named to distinguish, as follows:

//定义Module
@Module
public class FruitModule{
    @Named("typeA")
    @Provides
    public Fruit provideApple(){  //提供Apple给对应的mFruitA
        return new Apple();
    }
    @Named("typeB")
    @Provides
    public Fruit provdeBanana(){ //提供Banana给对应的mFruitB
        return new Banana()
    }
}
//定义Component
@Component(modules={FruitModule.class}) 
interface FruitComponent{    //Dagger根据接口自动生成FruitComponent
    void inject(Container container);   
}
//定义Container
class Container{
    @Named("typeA") //添加标记@Name("typeA"),只获取对应的@Name("typeA")的元依赖   @Inject
    Fruit mFruitA; 
    @Named("typeB") //添加标记@Name("typeA"),只获取对应的@Name("typeA")的依赖    @Inject
    Fruit mFruitB;
    ...
    public void init(){
         DaggerFruitComponent.creaete().inject(this); //使用FruitComponent的实现类注入
     }

}

Thus, only the same @Named @Inject member variables and methods can be @Provides association. 
If you think @Named can only be used to distinguish between string does not meet the requirements, you can also customize @Named similar comments, use meta-annotation @Qualifier can achieve this annotation, such as to achieve a distinction by type int @IntNamed

@Qualifier   //必须,表示IntNamed是用来做区分用途
@Documented           //规范要求是Documented,当然不写也问题不大,但是建议写,做提示作用
@Retention(RetentionPolicy.RUNTIME)  //规范要求是Runtime级别
public @interface IntNamed{
    int value();
}

Next, we define @IntNamed use to modify the above FruitA, FruitB examples are as follows

//定义Module
@Module
class FruitModule{
    @IntName(1)
    @Provides
    public Fruit provideApple(){  //提供Apple给对应的mFruitA
        return new Apple();
    }
    @IntName(2)
    @Provides
    public Fruit provdeBanana(){ //提供Banana给对应的mFruitB
        return new Banana()
    }
}
//定义Component
@Component(modules={FruitModule.class}) 
interface FruitComponent{    //Dagger根据接口自动生成FruitComponent
    void inject(Container container);   
}
//定义Container
class Container{
    @IntName(1) //添加标记@IntName(1),只获取对应的@IntName(1)的元依赖 
    @Inject
    Fruit mFruitA; 
    @IntName(2) //添加标记@IntName(2),只获取对应的@IntName(2)的依赖
    @Inject
    Fruit mFruitB;
    ...
    public void init(){
         DaggerFruitComponent.creaete().inject(this); //使用FruitComponent的实现类注入
     }

}

Component method defined rules

Examples 1) corresponding to the above apple container, Component method usually only one input parameter, corresponding to the required injection Container. Input parameters return type is void 
2) method of Component can no input parameters, but it has to return: 
Step1: Module instances returned will start pre-defined look, if no jump to Step2 
Step2: Use @Inject with such a configuration to generate the instance returned and injected into the formation but also recursive member variables and parameters of the belt @Inject. such as

//定义ComponentB
@Component(modules={××××××××})//1.假设Module中没有provideApp()方法,但有provideInfo()
interface ComponentB{
    Apple apple(); //2.实现类自动返回由Apple(info)构建的实现类
}
public class Apple{
    @Inject
    Apple(Info info){//被@Inject标记,使用这个构造器生成实例
        ...
    }
    Apple(){   //不会使用这个构造器,没有被@Inject标记
    }
}

The code generated DaggerComponetB ComponentB implementation class of calls which Apple () method automatically using Apple (info) to generate an instance constructor returns. 
3) Suppose ComponentA dependent ComponentB, B method return value must be defined to provide the missing dependency A 
codes as componentB following dependent ComponentA

//定义ComponentB
@Component(modules={××××××××})
interface ComponentB{
    ...
}
//定义ComponentA
@Component(dependencies={ComponentB.class},modules={××××××××})//使用dependencies
interface ComponentA{
    ...
}


Thus, when using injection ComponentA Container, if no corresponding dependent, you will find the ComponentB. However, ComponentB these must be explicitly supplied to the A depends not found A. How to provide it, you only need to add a method in ComponentB as follows

@Component(modules={××××××××})
interface ComponentB{
    // 假设A中module中找不到apple,banana,oranges,但是B的module有,B必须提供带返回值的方法如下
    Apple apple();
    Banana banana();
    Oranges oranges();
}


Container of the rules @Inject

. 1) can mark @Inject member variables in the Container, these variables member packet-level requirements are visible, that is not marked private @Inject member variable. 
2) When the flag @Inject member variable, dependent on the following rules to find the corresponding

1.该成员变量的依赖会从Module的@Provides方法集合中查找;
2.如果查找不到,则查找成员变量类型是否有@Inject构造方法,并注入构造方法且递归注入该类型的成员变量

powerful functions

If you say that Dagger2 plant can generate code to use Dagger2, so far-fetched. Dagger2 addition to generating facility code, there are other powerful features, these are also reasons Dagger2 use. 
Scope, Multibinding, Subcomponent, Provider and Lazy, which will be introduced in the next article.
--------------------- 
Author: ancient bell 
Source: CSDN 
Original: https: //blog.csdn.net/duo2005duo/article/details/50618171 
copyright notice : This article is a blogger original article, reproduced, please attach Bowen link!

Guess you like

Origin blog.csdn.net/qq_27981847/article/details/92586663