Android:Dagger2的使用

说明:

Dagger2作用在于自动创建实例,省去了手动new实例的代码。另一作用在于实现在mvc、mvp等架构下,各层解耦。

有如下两种方式:

方式一:用 @Inject + @Inject + @Component 方式实现,new的那个实例可以更改源码且能被实例化时适用。

方式二:用 @Inject +  (@Module + @Provides ) + @Component 方式实现,new的那个实例是三方jar包,不能改源码或不能被实例化时用这种方式。


一、加入依赖jar包:

在工程根/app目录下build.gradle中,加入依赖:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //dagger2依赖包
    compile 'com.google.dagger:dagger:2.+'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.+'
}


二、用 @Inject + @Inject + @Component 方式实现(此方式只适用于非第三方jar,即可以在被创建类的构造方法前加上@Inject):

1.在需要new的类构造方法上加@Inject:

/**
 * 网络请求API,供UserPresenter调用
 */
public class UserApi {

    /**
     * 加上@Inject,PresenterComponent类就可以创建实例
     */
    @Inject
    public UserApi() {
    }

    /**
     * 此方法供UserPresenter调用
     */
    public void getUserInfoByNet(String userId) {

    }
}

2.在使用的类的成员变量(属性注入)或方法(方法注入)加上@Inject:

/**
 * 业务类,供Activity调用
 */
public class UserPresenter {

    /**
     * 属性注入,此处@Inject与UserApi构造方法前的@Inject相对应
     */
    @Inject
    UserApi mUserApi;

//    /**
//     * 方法注入(在构造方法后执行),用方法注入时mUserApi前不能加@Inject,此处@Inject与UserApi构造方法前的@Inject相对应
//     */
//    @Inject
//    public void setUserApi(UserApi userApi) {
//        this.mUserApi = userApi;
//    }

    public UserPresenter() {
        //DaggerPresenterComponent是自动生成的,基于PresenterComponent接口,newInstance是PresenterComponent接口中定义的方法名
        DaggerPresenterComponent.create().newInstance(this);
    }

    /**
     * 此方法供调用api中的getUserInfoByNet方法
     */
    public void getUserInfoByPresenter(String userId) {
        //mUserApi实例会自动创建
        mUserApi.getUserInfoByNet(userId);
    }
}


3、创建连接组件Component,用于连接定义与创建:

/**
 * 此类用于创建UserApi实例(UserApi构造方法用@Inject标注),并注入给UserPresenter中定义的mUserApi变量(此变量用@Inject标注),UserApi是被创建者,UserPresenter是使用者(使用UserApi对象)
 */
@Component
public interface PresenterComponent {

    /**
     * 此方法名随意,外部调用方式:DaggerPresenterComponent.create().newInstance(this);
     */
    void newInstance(UserPresenter presenter);
}

三、 用 @Inject +  (@Module + @Provides ) + @Component 方式实现(创建三方jar包中的类创建时)

1.创建管理实例的类,类前加上@Module,每个创建三方类实例的方法加上@Provides:

/**
 * 此类用于创建三方jar包中的实例
 */
@Module
public class JarModule {

    /**
     * 此方法创建三方类实例,需要以@Provides标注,方法名随意
     */
    @Provides
    Socket newSocket() {
        return new Socket();
    }
}

2.在使用的类的成员变量(属性注入)或方法(方法注入)加上@Inject:

/**
 * 业务类,供Activity调用
 */
public class JarPresenter {

    /**
     * 属性注入,此处@Inject与JarModule标记了@Provides的方法相对应
     */
    @Inject
    Socket mSocket;

    public JarPresenter() {
        //DaggerJarComponent是自动生成的,基于JarComponent接口,newInstance是JarComponent接口中定义的方法名
        DaggerJarComponent.create().newInstance(this);
    }

    /**
     * 此方法供调用JarModule中的newSocket方法创建Socket实例
     */
    public Socket getSocket() {
        //mSocket实例会自动创建
        return mSocket;
    }
}


3、创建连接组件Component,用于连接定义与创建:

/**
 * 此类用于调用JarModule类中标记了@Provides的方法,创建对应的实例,modules可以有多个,以"modules=a.class,modues=b.class分隔
 */
@Component(modules = JarModule.class)
public interface JarComponent {

    /**
     * 此方法名随意,外部调用方式:DaggerJarComponent.create().newInstance(this);
     */
    void newInstance(JarPresenter presenter);
}

四、限定符@Named的使用(当创建实例的方法返回对象类型一样时,需要加@Named("标记名")进行区分):

1.创建管理实例的类,在创建对象的方法加@Named限定符,标记唯一性:

@Module
public class JarModule {

    /**
     * @Named("tag1"),tag1可以任意名称,用于创建实例时识别,与JarPresenter中的@Named("tag1")定义保持一样
     */
    @Named("tag1")
    @Provides
    Socket newSocket() {
        return null;
    }

    /**
     * @Named("任意名称"),用于创建实例时识别
     */
    @Named("tag2")
    @Provides
    Socket newServerSocket() {
        //...
        return null;
    }
}

2.在使用的类的成员变量(属性注入)或方法(方法注入)加上@Named,用于找到对应的方法:

public class JarPresenter {

    /**
     * @Named("tag1"),此参数跟JarModule中的@Named("newSocket")对应
     */
    @Inject
    @Named("tag1")
    public Socket mSocket;

    //...
}


五、限定符@Qualifier的使用(作用跟@Named一致,区别于使用自定义注解):

1.定义自定义注解:

/**
 * 自定义注解TAG1
 */
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface TAG1 {
}
/**
 * 自定义注解TAG2
 */
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface TAG2 {
}

2.像@Named一样使用:

(1)在创建实例的方法前加上自定义注解:

@Module
public class JarModule {

    /**
     * @TAG1为自定义注解,用于创建实例时识别,与JarPresenter中的@TAG1定义保持一样
     */
    @TAG1
    @Provides
    Socket newSocket() {
        return null;
    }

    /**
     * @TAG2为自定义注解,用于创建实例时识别,
     */
    @TAG2
    @Provides
    Socket newServerSocket() {
        return null;
    }
}


(2)在使用的类的成员变量(属性注入)或方法(方法注入)加上自定义注解,用于找到对应的方法:

public class JarPresenter {

    /**
     * @TAG1为自定义注解,此参数跟JarModule中的带有@TAG1注解的方法对应
     */
    @Inject
    @TAG1
    public Socket mSocket;

    //...
}

六、dependencies依赖的使用(属于@Component参数,定义Component基类,用于共享通用方法):

1.定义Module基类,将通用方法实现写在此类中:

/**
 * Module基类,此类定义通用方法,与BaseComponent中的定义保持一致
 */
@Module
public class BaseModule {
    /**
     * 此方法和BaseComponent中的newString方法保持一致
     */
    @Provides
    String newString() {
        return "新字符串";
    }
}

2.定义Component基类,将Module基类中的通用方法进行定义

/**
 * Component基类,此类定义通用方法,共享BaseModule中的newString方法
 */
@Component(modules = BaseModule.class)
public interface BaseComponent {
    /**
     * 此方法和BaseModule中的newString方法保持一致,不用加@Provides等注解
     */
    String newString();
}


3.定义Component子类,依赖Component基类,共享Module基类中的通用方法实现:

/**
 * 此类依赖BaseComponent基类,共用了newString方法,又能使用JarModule中的方法
 */
@Component(dependencies = BaseComponent.class, modules = JarModule.class)
public interface JarComponent {
    /**
     * 此方法名随意,外部调用方式:DaggerJarComponent.create().newInstance(this);
     */
    void newInstance(JarPresenter presenter);
}

4.使用Module基类中的通用方法创建实例:
/**
 * 业务类,供Activity调用
 */
public class JarPresenter {
    /**
     * 会调用BaseModule中的newString方法创建String实例
     */
    @Inject
    public String mStr;

    public JarPresenter() {
        //DaggerJarComponent和DaggerBaseComponent是自动生成的,基于JarComponent和BaseComponent接口,newInstance是JarComponent接口中定义的方法名
        DaggerJarComponent.builder().baseComponent(DaggerBaseComponent.create()).build().newInstance(this);
    }
}

七、Subcomponent依赖的使用(作用等同dependencies):

1.定义Module基类,将通用方法实现写在此类中:

/**
 * Module基类,此类定义通用方法,与BaseComponent中的定义保持一致
 */
@Module
public class BaseModule {
    /**
     * 此方法和BaseComponent中的newString方法保持一致
     */
    @Provides
    String newString() {
        return "新字符串";
    }
}

2.定义Component基类,将Module基类中的通用方法进行定义,并定义用于包含子Component类的方法:

/**
 * Component基类,此类定义通用方法,共享BaseModule中的newString方法
 */
@Component(modules = BaseModule.class)
public interface BaseComponent {
    /**
     * 此方法为BaseModule中的newString方法的定义
     */
    String newString();

    /**
     * 包含JarComponent类,JarComponent类必须为@Subcomponent注解,JarModule为JarComponent所关联的Module
     */
    JarComponent getJarComponent(JarModule module);
}


3.定义Component子类,依赖Component基类,共享Module基类中的通用方法实现:

/**
 * @Subcomponent表明此类被BaseComponent基类包含,共用了newString方法,又能使用JarModule中的方法
 */
@Subcomponent(modules = JarModule.class)
public interface JarComponent {
    /**
     * 此方法名随意,外部调用创建实例:DaggerBaseComponent.create().getJarComponent(new JarModule()).newInstance(this);
     */
    void newInstance(JarPresenter presenter);
}

4.使用Module基类中的通用方法创建实例:

/**
 * 业务类,供Activity调用
 */
public class JarPresenter {
    /**
     * 会调用BaseModule中的newString方法创建String实例
     */
    @Inject
    public String mStr;

    public JarPresenter() {
        //DaggerBaseComponent包含JarComponent,可调用JarComponent接口中定义的newInstance方法创建实例
        DaggerBaseComponent.create().getJarComponent(new JarModule()).newInstance(this);
    }
}


八、创建实例的作用域@Scope(在同一个对象如Activity内部创建多次,都只生成一个对象):

1.定义自定义的作用域注解:

/**
 * 自定义作用域注解ObjectScope,Module的方法和Component类前加上@ObjectScope,Module的方法创建出的实例为单例(前提:用@Inject标记的成员变量在同一个对象内,比如在同一个Activity内定义的)
 */
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ObjectScope {
}


2. 定义Module类,将创建实例的方法前加上自定义注解:

/**
 * 此类用于创建三方jar包中的实例
 */
@Module
public class JarModule {
    /**
     * @ObjectScope为自定义的作用域注解,跟JarComponent类的作用域注解保持一致
     */
    @ObjectScope
    @Provides
    UserApi newUserApi() {
        return new UserApi();
    }
}

3.定义 Component类,在类前加上自定义注解:

/**
 * @ObjectScope为自定义的作用域注解,跟JarModule类的newUserApi方法作用域注解保持一致
 */
@ObjectScope
@Component(modules = JarModule.class)
public interface JarComponent {
    /**
     * 此方法名随意,外部调用创建实例
     */
    void newInstance(JarPresenter presenter);
}


4.使用,在同一个对象内定义多个成员变量,该类只会创建一个实例:

/**
 * 业务类,供Activity调用
 */
public class JarPresenter {
    /**
     * 加了作用域后,在JarPresenter对象内,成员变量mUserApi1和mUserApi2为同个对象,
     */
    @Inject
    public UserApi mUserApi1;
    @Inject
    public UserApi mUserApi2;

    public JarPresenter() {
        //DaggerJarComponent为自定义类
        DaggerJarComponent.create().newInstance(this);
    }
}


九、Lazy使用(懒加载,在使用此成员变量时,要调用.get方法,才会创建此变量的实例):

public class JarPresenter {
    /**
     * 用Lazy<类>括起来的变量,只有在调用.get()方法时才会创建实例
     */
    @Inject
    public Lazy<UserApi> mUserApi;

    public JarPresenter() {
        //...
    }

    public UserApi getUserApi(){
        return mUserApi.get();
    }
}





猜你喜欢

转载自blog.csdn.net/a526001650a/article/details/78879628