开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 9 天,点击查看活动详情
首先我们了解一下如何写Component的构造函数,我们之前的文章里面都没有关于component的构造,但是我们看看dagger给我们实现的里面:
public static Builder builder() {
return new Builder();
}
public static ExampleComponent create() {
return new Builder().build();
}
Builder类:
public static final class Builder {
private ExampleModule exampleModule;
private Builder() {
}
public Builder exampleModule(ExampleModule exampleModule) {
this.exampleModule = Preconditions.checkNotNull(exampleModule);
return this;
}
public ExampleComponent build() {
if (exampleModule == null) {
this.exampleModule = new ExampleModule();
}
return new ExampleComponentImpl(exampleModule);
}
}
这里需要注意一下Component是通过build构造的。既然实现里面有这个,那我们是不是可以在Component里面去自定义自己的Build和Create呢?在创建的时候做一些我们自己的事情?首先我们写一个自己的Build类:
@Component.Builder
interface Builder {
fun build(): ExampleComponent
}
需要注意的是定义的这个Interface必须要加上@Component.Builder,要不然Dagger2是不认识的。再看看生成的代码:
private static final class Builder implements ExampleComponent.Builder {
@Override
public ExampleComponent build() {
return new ExampleComponentImpl(new ExampleModule());
}
}
这里就会有相应的一个实现。
下面再看看Create方法如何实现:
@Component.Factory
interface Factory{
fun create():ExampleComponent
}
这里就需要加上@Component.Factory关键字,并且build类也不能再要了。再看看实现:
private static final class Factory implements ExampleComponent.Factory {
@Override
public ExampleComponent create() {
return new ExampleComponentImpl(new ExampleModule());
}
}
这样就实现component的自定义构造啦,builder方法以及factory方法都可以。问题我们为什么要自定义构造呢?其实我们是想做一些事情,我们是想在Component实例化的时候传一些参数进去,这个时候我们就需要使用到@BindsInstance关键字啦!
比如我们想在构造里面绑定一个context,context是我们几乎每个模块都需要使用的,如果我给当前的Component绑定了,那么其他地方就可以随意使用了。我们先看看怎么给builder里面绑定:
@Component.Builder
interface Builder {
@BindsInstance
fun setContext(context: Context):Builder
fun build(): ExampleComponent
}
其实就是在一个方法前面加@BindsInstance就可以了,如果不加@BindsInstance编译的时候就会报错的哦。再看看生成的类:
private static final class Builder implements ExampleComponent.Builder {
private Context setContext;
@Override
public Builder setContext(Context context) {
this.setContext = Preconditions.checkNotNull(context);
return this;
}
@Override
public ExampleComponent build() {
Preconditions.checkBuilderRequirement(setContext, Context.class);
return new ExampleComponentImpl(new ExampleModule(), setContext);
}
}
竟然把setContext作为了参数!那命名上还是注意一点吧。还有一点就是setContext一定要返回Builder,要不然在调用了这个方法之后就没有办法链式调用了,那在注入的时候也需要传入context这个参数了:
DaggerExampleComponent.builder().setContext(this.applicationContext).build().inject(this)
那既然传入了我该如何使用这个context呢?
其实很简单在其他注入对象要使用context的地方,这个context就会被用起来,例如我们上次定义的Woman这个类加入context:
@ExampleScope
@Provides
@Named("Woman")
fun providerWoman(context: Context):Person{
return Woman()
}
在dagger2生成的代码里面就变成这个样子了:
private void initialize(final ExampleModule exampleModuleParam, final Context setContextParam) {
this.setContextProvider = InstanceFactory.create(setContextParam);
this.providerWomanProvider = DoubleCheck.provider(ExampleModule_ProviderWomanFactory.create(exampleModuleParam, setContextProvider));
}
它就会把context传入了。