Dagger2使用简析——简单注入
NOTE1 : Dagger2的官网地址: https://google.github.io/dagger/
NOTE2 : 使用前请先了解JAVA中的注解基本知识,如果对实现原理感兴趣可以了解下APT技术(不了解也不影响正常使用)
一切实践从问题出发,首先我们来解决第一个问题,
1. 如何使用Dagger2注入一个简单对象到目标类中
让我们先复制一个示例,它包含下面三部分
@Module
public class MainModule {
@Provides
public Product provideProduct() {
return new Product();
}
}
@Component(modules = {MainModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Product mProduct;
@Override
protected void onCreate(Bundle savedInstanceState) {
//...省略无关代码
DaggerMainComponent
.builder()
.build()
.inject(this);
mProduct.create();
}
}
我们依次对三个部分所涉及的内容进行解释:
1.1 @Module
@Module
注解用于获取对象实例的类,Dagger2根据该注解知道应该去哪个类里获取对象实例
1.2 @Provides
@Provides
注解用于module类中获取对象实例的方法,Dagger2根据该注解及方法的返回值类型将对象实例注入到对应的引用中
1.3 @Inject
@Inject
用于注解构造函数或成员变量
-
当作用于成员变量时,Dagger2根据该注解及成员变量的类型,从moudle中得到相应实例。
注意:成员变量的访问修饰符不能是private -
当作用于构造函数时,就是Dagger2对于获取对象实例的第二种方式,比如上面的例子其实可以直接在
Product
的构造函数上注解@Inject
,并移除@Provides
注解的方法@Inject public Product() { }
但是
@Inject
并非适用于所有的地方,比如以下三种情况:- 不具有构造函数的接口
- 远程引入的三方库中的类无法被添加注解
- 通过建造者模式等方式可配置化的进行构造的对象
而使用
@Provides
可以更好的处理这些问题
1.4 @Component
@Component
注解用于担任连接桥梁的接口,其两端分别是在@Component的参数中指定的modules数组
和在方法参数中指定的具体类
注意:方法参数必须是要注入的具体类,而非其父类或接口
1.5 DaggerMainComponent
在创建Module和Component后,我们需要build ——> Make Project
,这样APT会在指定目录下生成对应的java文件,其中就会包含名如DaggerXX
的的文件,它实现了我们所创建的Component接口,最终要完成注入,只需要像这样调用:
DaggerMainComponent
.builder()
.build()
.inject(this);
2. 简单分析自动生成的代码
2.1 DaggerXX类
public final class DaggerMainComponent implements MainComponent {
private final MainModule mainModule;
private DaggerMainComponent(MainModule mainModuleParam) {
this.mainModule = mainModuleParam;
}
public static Builder builder() {
return new Builder();
}
public static MainComponent create() {
return new Builder().build();
}
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMProduct(
instance, MainModule_ProvideProductFactory.provideProduct(mainModule));
return instance;
}
public static final class Builder {
private MainModule mainModule;
private Builder() {}
public Builder mainModule(MainModule mainModule) {
this.mainModule = Preconditions.checkNotNull(mainModule);
return this;
}
public mainComponent build() {
if (mainModule == null) {
this.mainModule = new mainModule();
}
return new DaggerMainComponent(mainModule);
}
}
}
它实现了我们所创建的Component接口,内部使用了建造者模式
,方便根据不同需求构建该对象实例,比如我们可以传入module实例替换默认的无参实例,关键看一下我们定义的inject
方法的具体实现。
2.2 MainActivity_MembersInjector类和MainModule_ProvideProductFactory类
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
//...省略无关代码
public static void injectMProduct(MainActivity instance, Product mProduct) {
instance.mProduct = mProduct;
}
}
public final class MainModule_ProvideProductFactory implements Factory<Product> {
//...省略无关代码
public static Product provideProduct(MainModule instance) {
return Preconditions.checkNotNull(
instance.provideProduct(), "Cannot return null from a non-@Nullable @Provides method");
}
}
其实关键的方法就是injectMProduct()
和provideProduct()
,一看就懂,没什么可细说的。
3. 含有参数(依赖关系)的构造
当Product
必须与Worker
关联时,有如下构造函数
public Product(Worker worker) {
mWorker = worker;
}
此时我们提供Product
实例对象时需要作出以下修改
@Provides
public Product provideProduct(Worker worker) {
return new Product(worker);
}
即我们需要传入Worker
来构建Product,那么Worker
实例如何提供呢?其实同样的,我们可以使用简单构造时的两种方式提供Worker
实例,具体就不在赘述,可以自行实践。
下一篇
,我们将对问题进行升级,并了解@Scope、@Qualifier、@binds、dependencies、Lazy的使用