美文网首页
Dagger2使用入门

Dagger2使用入门

作者: 天神Deity | 来源:发表于2017-11-05 17:42 被阅读9次

    推荐Dagger2 不错的入门系列传送门:http://www.jianshu.com/p/cd2c1c9f68d4
    官网说明文档:https://google.github.io/dagger/users-guide.html

    • Dagger 声明依赖
      Dagger可帮你的应用构造类的实例,并满足它们的依赖关系.它使用javax.inject.Inject注释来标识它感兴趣的构造函数和字段属性。
      一个类需Dagger为其创建实例那么需要为这个类的构造函数添加@Inject注解.当Dagger需要为一个类创建实例时,Dagger会去获取构造函数内参数(也有可能是无参构造函数)并调用对应的构造方法,就像下面这样:
    class Thermosiphon implements Pump {
      private final Heater heater;
    
      @Inject
      Thermosiphon(Heater heater) {
        this.heater = heater;
      }
    
      ...
    }
    

    Dagger可以直接使用@Inject注解获取到属性实例,例如下面的例子中通过@Inject属性获取到了heater和pump的实例.

    class CoffeeMaker {
      @Inject Heater heater;
      @Inject Pump pump;
    
      ...
    }
    

    Dagger也可以进行方法注入,不过一般构造函数或字段注入通常是首选.

    满足依赖

    通常情况下,当你需要一个对应类的实例时,Dagger调用该类的构造函数来创建实例,并将该实例赋值给被@Inject注解的属性字段中.然后实际中的开发任务也有@Inject无法触及的内容:

    1. 接口不能被构造
    2. 第三方类不能注释
    3. 可配置的对象

    对于这些@Inject够不着的尴尬情况,请使用 @Provides
    注释方法来满足依赖关系。 方法的返回类型定义了它满足哪个依赖关系。如下示例,当需要创建Heater 实例时,provideHeater()将被调用

    @Provides 
    static Heater provideHeater() {
      return new ElectricHeater();
    }
    

    @Provides方法有可能拥有自己的依赖关系,以下代码片段中(providePump()方法拥有自己的依赖关系,Thermosiphon 参数),该方法会返回一个这个Thermosiphon实例.

    @Provides 
    static Pump providePump(Thermosiphon pump) {
      return pump;
    }
    

    @Provides配合 @Module方法一起使用,@Provides一般在被@Module注解的类下使用,例如下面的代码片段:

    @Module
    class DripCoffeeModule {
    @Provides 
    static Heater provideHeater() {
        return new ElectricHeater();
      }
    
    @Provides 
    static Pump providePump(Thermosiphon pump) {
        return pump;
      }
    }
    

    按照惯例,被@Provides注解的方法使用provide 前缀,被@Module注解的类使用module作为后缀.

    • 总结:

    一、@Inject 注解 可以用来标准构造函数,同时它也可以被用来标注对象的实例

    二、被@Inject标注的对象实例与被@Inject标注的构造函数 通过@Component产生联系(这样对象实例就可以找到自己的构造函数进行初始化了)

    三、@Module注解是为第三方类库而生的.在第三方类库上使用Dagger2稍微不同的地方是第三方类库的构造函数使用@Provides注解

    四、使用@Inject标注的构造函数(自身代码)与使用@Module+@Provides标注的构造函数 都可以创建 对象实例,@Component 会优先使用@Module+@Provides创建的实例(如果存在的话)

    五、当出现有多个@Inject标注的构造函数(或者多个@Module+@Provides标注的构造函数),使用@Qualifier 注解来区分所需使用的构造函数(类似于唯一标识符)

    2018年6月15日17:58:30 更新:

    1.初步使用

    试验用实体类
    package com.keytop.test.entity;
    
    import javax.inject.Inject;
    
    /**
     * 创建实体
     * Create by fengwenhua at 2018/6/15
     **/
    public class User {
        private String name;
    
    
        @Inject
        public User(String name){
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    在该实体的构造函数中,我们通过@Inject注解告诉Dagger,如果需要User实例,可以使用该构造函数生成

    实例生产者
    package com.keytop.test.module;
    
    import com.keytop.test.entity.User;
    
    import dagger.Module;
    import dagger.Provides;
    
    /**
     * Module 实例生产者
     * Create by fengwenhua at 2018/6/15
     **/
    
    @Module
    public class MainModule {
    
        @Provides
        public User providerUser(){
            return new User("姬如雪");
        }
    }
    

    使用@Module注解该类,使用@Provides注解生产方法,实例的生产者有个约定,以Module结尾,方法以provider开头,当然如果你不遵守也是可以的.

    package com.keytop.test.component;
    
    import com.keytop.test.MainActivity;
    import com.keytop.test.module.MainModule;
    
    import dagger.Component;
    
    /**
     * 连接纽带
     * Create by fengwenhua at 2018/6/15
     **/
    @Component(modules = {MainModule.class})
    public interface MainComponent {
    
        void inject(MainActivity activity);
        
       //在User 中是没有@Inject注解,因此在代理类中,这个方法其实是废方法哦.
        void inject2(User user);
    }
    
    

    inject(MainActivity activity)这个方法其实你可随便命名,真正在编译的时候,Dagger会检测参数中(在这就是MainActivity )使用有@Inject注解.如果有的话,进行参数注入。否则的它做个有趣的操作,生成个虚构的注入方法.

    @Override
      public void inject2(User user) {
        MembersInjectors.<User>noOp().injectMembers(user);//代理类中的废方法
      }
    

    使用

    package com.keytop.test;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    import com.keytop.test.component.DaggerMainComponent;
    import com.keytop.test.entity.User;
    import com.keytop.test.module.MainModule;
    
    import javax.inject.Inject;
    
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = MainActivity.class.getSimpleName();
    
        @Inject
        protected User user;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(MainActivity.this);
            // 话说以下的使用方式也没问题,因为当你未指定mainModule时,build()会帮你调用一个无参的构造类
            //DaggerMainComponent.builder().build().inject(MainActivity.this);
            Log(user.getName());
        }
    
        protected void Log(String message){
            Log.i(TAG, message);
        }
    
    }
    
    运行结果

    于2018年7月5日20:04:13更新

    2. 模拟调用第三方库

    当调用第三方库时,一般情况下我们是没办法去修改它们的源码,因此我们也就没办法给实体类添加@Inject注解了.下面我们引入一个Job类来模拟第三方库调用,我们不准备在其上修改任何代码.它就是一个普通的POJO类.

    package com.keytop.test.entity;
    
    /**
     * 职业
     * Create by fengwenhua at 2018/7/5
     **/
    public class Job {
    
        /**职业名称*/
        private String jobName;
    
        public String getJobName() {
            return jobName;
        }
    
        public void setJobName(String jobName) {
            this.jobName = jobName;
        }
    }
    

    相关文章

      网友评论

          本文标题:Dagger2使用入门

          本文链接:https://www.haomeiwen.com/subject/zqsbmttx.html