Dagger2使用入门

推荐Dagger2 不错的入门系列传送门://www.greatytc.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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容