Dagger2的简单使用总结

 

一,引入dagger2 到项目中

1,第一步 配置project 目录下的gradle;

13.0之前引入插件如图所示

 

      

内容如下:

  classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'

 

     

     23.0 之后无需任何操作,只需要配置APP目录下的gradle即可

      

2,第二步 配置APP 目录下的gradle

   13.0之前版本为

 

   内容如下:

 compile 'com.google.dagger:dagger:2.4'

       apt 'com.google.dagger:dagger-compiler:2.4'

  Provided'org.glassfish:javax.annotation:10.0-b28'

 

23.0以后的gradle 版本

直接在dependencies下添加

 

compile 'com.google.dagger:dagger:2.4'
annotationProcessor "com.google.dagger:dagger-compiler:2.4"
compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解库



 

最后就sync now 就完成了dagger 在项目中的引入。

 

  dagger2的基本用法

1,基本的注解用法

1. 编写一个需要注入到view层的实体类

写一个textbean类用作依赖对象,包含一个content属性

public class TextBean {
    private  String  content;
    public String getContent() {
        return content;   }
    public void setContent(String content) {
        this.content = content;

}}

2. 写一个Module

     假如我们的需求是想在MainActivity里获取到一个实例化完成,并且它的content属性有内容的TextBean对象,那么这个Module 相当一个加工厂,把我们需要的对象给我们创建出来。代码如下:

@Module //module的注解标记
public class MainMoudle {
    @Provides //提供返回我们想要的Textbean的方法的注释标记
    @Singleton //单例的注释标记
        public TextBean getTextBean( ){
        TextBean textBean=new TextBean( );
        textBean.setContent("我的daager2 第一个实体");
        return  textBean;
    }
 }

(1)@Module以表明该类是Module类,这样Dagger2才能识别.

 

(2)@Provides的作用是声明Module类中哪些方法是用来提供依赖对象的

 

Component类需要依赖对象时,他就会根据返回值的类型来在有@Provides注解的方法中选择调用哪个方法.在一个方法上声明@Provides注解,就相当于创建了一条生产线,这条生产线的产物就是方法的返回值类型.有了这条生产线,供应商就能提供这种类型的商品了,当商店老板发现有人需要这种类型的商品时,供应商就可以提供给他了

3. 写一个Component接口

@Component(modules = MainMoudle.class)//绑定对应的module类
public interface MainCompont {
    void inject(MainActivity mainActivity);//注入方法

}

1)@Component注解有modules和dependencies两个属性,

这两个属性的类型都是Class数组,

1, modules的作用就是声明该Component含有哪几个Module,当Component 需要 某个依赖对象时,就会通过这些Module类中对应的方法获取依赖对象 

 

2,dependencies属性则是声明Component类的依赖关系

 

4. MainActivity中声明


public class MainActivity extends AppCompatActivity {
    private TextView  textView;
        @Inject
        TextBean textBean;
   

 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        MainCompont mainCompont=    DaggerMainCompont.builder().mainMoudle(new MainMoudle( )).build();


        mainCompont.inject(this);
        // 子类依赖对象 ,并注入
       textView= ((TextView) findViewById(R.id.my_name_tv_id));
               textView.setText(textBean.getContent());
        Log.e("Dagger2的检测one ",textBean.toString());
    
    }

 

 

执行结果:

 

 

基本用法总结图

 

 

 

 

 

 

 

 

 

 

 

 

  dagger2的其他注解用法

1.@Named和@Qulifier注解的使用

 使用场景 如果两个@Provides的注释的方法,返回值的类型是一样的,那么在MainActivity里的两个@Inject 注入的同一个实体类型对象时候,

要通过@Named区分,或者通过@Qulifier自定义注解:不然就会报错无法编译

一,通过@named区分

1.对于Moudle类的注入类

@Provides
@Singleton
@Named("textone")
public TextBean getTextBean( ){
    TextBean textBean=new TextBean( );
    textBean.setContent("我的daager2 第一个实体");
    return  textBean;
}
@Provides
@Singleton
@Named("texttwo")
public TextBean getTextBean2(){
    TextBean textBean=new TextBean( );
    textBean.setContent("我的dagger2 第一个实体的第二个procides的方法");
    return  textBean;
}

 

2.对于MainActivity的注入类

public class MainActivity extends AppCompatActivity {
    private TextView  textView;
    private Button  buttons;
    @Inject
    @Named("textone")
    TextBean textBean;
    @Inject
    @Named("texttwo")
    TextBean textBean2;

    @Inject
    TwoBean twoBean;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        MainCompont mainCompont=  DaggerMainCompont.builder().mainMoudle(new MainMoudle( )).build();
        mainCompont.inject(this);
        // 子类依赖对象 ,并注入
       textView= ((TextView) findViewById(R.id.my_name_tv_id));
        buttons= ((Button) findViewById(R.id.onclick_bt_id));
        textView.setText(textBean.getContent());
        Log.e("Dagger2的检测one ",textBean.toString()+"two id="+textBean2.toString());
        Log.e("Dagger2的第二个实体  ",twoBean.getContent()+"____id="+twoBean.toString());
                   }
        });

    }



}

 

 

二,通过@Qulifier自定义注解区分

@Qulifier功能和@Named一样,并且@Named就是继承@Qulifier

 

1. 自定义注解接口内容

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface TextonePri {
}

2. Module类使用

@Provides
@Singleton
@TextonePri
public TextBean getTextBean( ){
    TextBean textBean=new TextBean( );
    textBean.setContent("我的daager2 第一个实体");
    return  textBean;
}

3,在注入类,MainActivity的使用

 @Inject
 @TextonePri
TextBean textBean;
@Inject
@Named("texttwo")
TextBean textBean2;

 

2.Scope

在前面中提到@Singleton注解,该注解能够使同一个Component中的对象保持唯一,即单例。

 如下方式:

    @Provides // 关键字,标明该方法提供依赖对象

    @Singleton

    Person providerPerson(Context context){

 

        return new Person(context);

    }

 Module中,对应方法中添加@Singleton注解,同时其所在的Component中,类生命上也需要添加注解

@Singleton

@Component(modules = MainModule.class)  // 作为桥梁,沟通调用者和依赖对象库public interface MainComponent {

}

 如果我们看这个意思,感觉其内部应该做了很多的实现,用以达到单例。其实,没我们想的那么复杂。

看一下@Singleton的实现

@Scope //注明是Scope

  @Documented  //标记在文档

@Retention(RUNTIME)  // 运行时级别

public @interface Singleton {}

通过@Scope定义的一个新的注解。

在之前的,我们知道该单例是依托于他所在的Component组件。那么我们是否可以这样理解,因为方法上添加的@Scope标记的注解和Component上添加的@Scope标记的注解相同(确实相同,同为@Singleton),就表明了该方法提供的实例对象在Component保持唯一。保持唯一的条件是通过@Scope标记的注解相同。

通过在上面的依赖层级上,Android中通常定义两个生命周期。

全局的生命周期PerApp

/**

 * 全局的生命周期单例

 */@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerApp {

 

}

 在使用中完全和@Singleton相同。

@Modulepublic class AppModule {

 

    private Context mContext;

 

    public AppModule(Context context){

        mContext = context;

    }

 

    @Provides

    @PerApp  // 添加该标记表明该方法只产生一个实例

    Context providesContext(){

        // 提供上下文对象

        return mContext;

    }

 

}

 @PerApp // 因为Module 中使用了该标记,所以需要在此添加@Component(modules = AppModule.class)public interface AppComponent {

 

    // 向其下层提供Context 对象

    Context proContext();

}

 因为单例的依托于他所在的Component中,所以需要在Application中进行实例化。

public class App extends Application {

 

    // 为什么可以使用静态

    public static AppComponent appComponent;

 

 

    @Override

    public void onCreate() {

        super.onCreate();

 

        // 实例化

        appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();

 

    }

}

 为什么可以使用静态的,因为该AppComponent对象的生命周期是整个App。那么在使用中,其所在Module中的实例化对象,可以保持全局单例。

一个Activity的生命周期PerActivity

有全局的单例,而对于一个Activity,他也有些对象需要保持单例。我们需要定义该注解。

/**

 * Activity 单例生命周期

 */@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerActivity {

}

 会发现,除了定义名不一样,其余都和PerApp一样。在前面,说过这样一句话:保持唯一的条件是通过@Scope标记的注解相同。

@Modulepublic class ActivityMoudule {

 

    @PersonForContext

    @Provides

    @PerActivity  // 添加标记,生命其所构造的对象单例

    Person providePersonContext(Context context){

        // 此方法需要Context 对象

        return new Person(context);

    }

 

    .....

}

 @PerActivity  // ActivityMoudule 中使用了该标记@Component(dependencies = AppComponent.class,modules = ActivityMoudule.class)public interface ActivityComponent {

 

    // 注入

    void inject(MainActivity activity);

}

   使用方式,因为其所保持的单例是在Activity中,具体使用如下。

public class MainActivity extends AppCompatActivity{

 

    @PersonForContext // 标记

    @Inject

    Person person;

 

 

    @PersonForName // 标记

    @Inject

    Person person2;

 

 

    /**

     * 不使用静态的,因为该Component只是针对于该Activity,而不是全局的

     */

    ActivityComponent  activityComponent;

 

 

    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

 

        setContentView(R.layout.activity_main);

 

 

        activityComponent = DaggerActivityComponent.builder()

                .appComponent(App.appComponent)  // 添加了全局的AppComponent组件,可以使用全局的实例化对象

                .activityMoudule(new ActivityMoudule())

                .build();

 

 

        activityComponent.inject(this);

 

 对于具有依赖关系的Component,不能使用相同的Scope,如果使用相同的会带来语意不明

3懒加载Lazy和强制重新加载Provider

public class MainActivity extends AppCompatActivity{

 

    @PersonForContext // 标记

    @Inject

    Lazy lazyPerson; // 注入Lazy元素

 

 

    @PersonForName // 标记

    @Inject

    Provider providerPerson; // 注入Provider

 

 

    /**

     * 不使用静态的,因为该Component只是针对于该Activity,而不是全局的

     */

    ActivityComponent  activityComponent;

 

 

    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

 

        setContentView(R.layout.activity_main);

 

 

        activityComponent = DaggerActivityComponent.builder()

                .appComponent(App.appComponent)  // 添加了全局的AppComponent组件

                .activityMoudule(new ActivityMoudule())

                .build();

 

 

        activityComponent.inject(this);

 

 

        Person person = lazyPerson.get();// 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象

 

 

        // 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。

        Person person1 = providerPerson.get();

    }

}

 

 

参考链接:

https://www.jianshu.com/p/1d84ba23f4d2

 

  https://blog.csdn.net/lisdye2/article/details/51942511

 

  https://dreamerhome.github.io/2016/07/07/dagger/?utm_source=tuicool

 

你可能感兴趣的:(Dagger2的简单使用总结)