推荐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无法触及的内容:
- 接口不能被构造
- 第三方类不能注释
- 可配置的对象
对于这些@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;
}
}