Component Builder
在前面咱们提到,假如Dagger想要运用或许支持注入由外界供给的目标时,需求经过手动创立Module,传入外界目标,然后再将module目标设置给Component。
@Module
class CommonModule(
private val context: Context
) {
@Provides
fun context(): Context = context
@Provides
fun provideSharedPreferences(): SharedPreferences {
return context.getSharedPreferences("SP_FILE", Context.MODE_PRIVATE)
}
}
@Component(modules = [CommonModule::class])
interface AppComponent {
fun inject(application: MyApplication)
}
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.commonModule(CommonModule(this))
.build()
.inject(this)
...
}
}
在上面的例子中,DaggerAppComponent.builder()
用于获取DaggerAppComponent
的制作者实例,用于对DaggerAppComponent
的实例进行一些装备。
当没有特殊声明时,Dagger会主动为Component生成对应的Builder,并且Dagger会主动检索该Component依靠的Module和Component,在Builder中为每一个Module和Component生成setter
。
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private CommonModule commonModule;
private BaseComponent baseComponent;
private Builder() { }
public Builder commonModule(CommonModule commonModule) {
this.commonModule = Preconditions.checkNotNull(commonModule);
return this;
}
public Builder baseComponent(BaseComponent baseComponent) {
this.baseComponent = Preconditions.checkNotNull(baseComponent);
return this;
}
public MyComponent build() {
Preconditions.checkBuilderRequirement(commonModule, AModule.class);
Preconditions.checkBuilderRequirement(baseComponent, BComponent.class);
return new MyComponentImpl(commonModule, baseComponent);
}
}
咱们也能够对Component的Builder进行显式声明,以复用一些代码或许将依靠Module和Component的初始化逻辑收拢:
@Component(modules = [CommonModule::class])
interface AppComponent {
fun inject(application: MyApplication)
// Subcomponent需求运用@Subcomponent.Builder
// 关于Subcomponent的更多介绍参见后文[Component之间依靠项的复用]。
@Component.Builder
abstract class Builder : BaseBuilder<AppComponent> {
fun context(context: Context): Builder {
return setCommonModule(CommonModule(context))
}
protected abstract fun setCommonModule(module: CommonModule): Builder
}
}
DaggerAppComponent.builder()
.context(this)
.build()
.inject(this)
需求留意的是,显式声明Builder时,咱们有必要为Component依靠
和没有默许结构函数的Module依靠
界说setter
,不然将编译失利;并且在运用Builder结构Component时,也有必要调用这些setter,不然将会抛出运行时过错。
Component Factory
除了运用Builder来定制Component外,Dagger还供给了Component Factory办法来定制Component。
那么已然已经有Builder了,为何还要供给Factory呢?
既生Builder,何生Factory?
这是由于Builder办法在运用上有一些不方便,当咱们要结构的Component有多个依靠的Module和Component时,Component依靠
和没有默许结构函数的Module依靠
有必要要手动调用setter
,然后才干调用build
函数生成Component实例。而咱们在运用时很容易忘记某个setter
的调用,这种过错又不会在编译期间被检测出来,仅在运行时抛出过错。
因而,Dagger供给了Factory,经过严格约束Factory中create办法的参数为Component依靠的Module和Component实例,将原本在运行时的查看提前到了编译时,从而提升了运用体验。
接下来让咱们看看怎么运用Component Factory。
怎么运用
和Builder不相同,默许情况下Dagger并不会为Component生成相应的Factory完成,咱们需求显式的为Component声明Factory:
@Component(
modules = [CommonModule::class],
dependencies = [BaseComponent::class]
)
interface AppComponent {
fun inject(application: MyApplication)
// Subcomponent需求运用@Subcomponent.Factory。
@Component.Factory
interface Factory {
// Factory中只能界说一个办法,且该办法承受Component依靠的Module和Component,
// 回来Component实例。
fun create(
baseComponent: BaseComponent,
commonModule: CommonModule
): MyComponent
}
}
与Builder相同,咱们也有必要在create
办法中将Component依靠
和没有默许结构函数的Module依靠
作为参数传递,不然将会编译过错。
编译后Dagger就会主动为咱们生成当时Component对应的Factory完成类:
public static MyComponent.Factory factory() {
return new Factory();
}
private static final class Factory implements MyComponent.Factory {
@Override
public MyComponent create(BaseComponent baseComponent, CommonModule commonModule) {
Preconditions.checkNotNull(baseComponent);
Preconditions.checkNotNull(commonModule);
return new MyComponentImpl(commonModule, baseComponent);
}
}
运用时和Builder类似,经过factory
静态办法获取工厂实例,调用create
办法即可:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory()
.create(baseComponent, CommonModule(this))
.inject(this)
...
}
}
将外部目标添加到Dagger中的简便办法
让咱们回到文章开端的例子中,为了向Dagger中供给Context
,不管运用Builder仍是Factory,咱们都不得不为其创立一个CommonModule
实例,然后设置给AppComponent
,这个步骤多少仍是有些繁琐,因而Dagger为咱们供给了一个新的注解@BindsInstance
用于直接将外部目标绑定到Dagger上。
@BindsInstance
有两种运用办法:
在Builder中运用
@Component(modules = [PrefModule::class])
interface AppComponent {
fun inject(application: MyApplication)
@Component.Builder
interface Builder {
@BindsInstance
fun context(context: Context): Builder
// 有默许结构函数的Module能够省略setter界说
// fun prefModule(module: PrefModule): Builder
fun build(): MyComponent
}
}
// module中不再需求context的Provides-method
@Module
class PrefModule {
@Provides
fun provideSharedPreferences(
context: Context // context现在能够作为依靠项直接注入了
): SharedPreferences {
return context.getSharedPreferences("SP_FILE", Context.MODE_PRIVATE)
}
}
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.context(this)
.build()
.inject(this)
...
}
}
在Factory中运用
@Component(modules = [PrefModule::class])
interface AppComponent {
fun inject(application: MyApplication)
@Component.Factory
interface Factory {
fun create(
@BindsInstance context: Context
// 相同的有默许结构函数的Module能够省略
// , prefModule: PrefModule
): MyComponent
}
}
// module中不再需求context的Provides-method
@Module
class PrefModule {
@Provides
fun provideSharedPreferences(
context: Context // context现在能够作为依靠项直接注入了
): SharedPreferences {
return context.getSharedPreferences("SP_FILE", Context.MODE_PRIVATE)
}
}
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory()
.create(this)
.inject(this)
...
}
}