开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情
所谓scope是一个范围,Dagger2提供一个@Singleton,也可以自定义自己的scope,scope的作用就是为了限制实例的范围。Dagger2提供的Singleton并不是全局的Singleton,而是scope范围内的Singleton。
下面看@Singleton的一个使用例子:
如果需要提供一个单实例:
@Module
class ExampleModule {
@Provides
@Named("Man")
fun providerMan():Person{
return Man()
}
@Singleton
@Provides
@Named("Woman")
fun providerWoman():Person{
return Woman()
}
}
那么在Module相关的Component上面也需要加上这个关键字:
@Singleton
@Component(modules = [ExampleModule::class])
interface ExampleComponent {
fun inject(mainActivity: MainActivity)
}
然后在使用的地方,我们打印一下两个对象的地址:
@Inject
@Named("Woman")
lateinit var p1: Person
@Inject
@Named("Woman")
lateinit var p2: Person
Log.i("daggerExample","p1 address:$p1")
Log.i("daggerExample","p2 address:$p2")
打印结果:
I/daggerExample: p1 address:com.laworks.dagger2example.Woman@1a159c6
I/daggerExample: p2 address:com.laworks.dagger2example.Woman@1a159c6
从上面的结果可以看出两个的地址是一样的。深入研究一下,我们看看dagger2生成的代码。为了方便确认,我们在使用的地方增加两个Man的实例:
@Inject
@Named("Woman")
lateinit var p1: Person
@Inject
@Named("Woman")
lateinit var p2: Person
@Inject
@Named("Man")
lateinit var p3: Person
@Inject
@Named("Man")
lateinit var p4: Person
Woman是Singleton的而Man不是,看看Dagger生成的文件:
private void initialize(final ExampleModule exampleModuleParam) {
this.providerWomanProvider = DoubleCheck.provider(ExampleModule_ProviderWomanFactory.create(exampleModuleParam));
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMyFamily(instance, new MyFamily());
MainActivity_MembersInjector.injectP1(instance, providerWomanProvider.get());
MainActivity_MembersInjector.injectP2(instance, providerWomanProvider.get());
MainActivity_MembersInjector.injectP3(instance, ExampleModule_ProviderManFactory.providerMan(exampleModule));
MainActivity_MembersInjector.injectP4(instance, ExampleModule_ProviderManFactory.providerMan(exampleModule));
return instance;
}
这个是DaggerExampleComponent类,可以看出在DaggerExampleComponent初始化的时候Woman这个类已经构建好了,Man只是在Activity Inject的时候创建的多个实例。这个我们就知道为什么Woman是一个地址的原因了。
@Singleton是官方给的,如果我们需要在不同的Component之间使用局部的单例该如何做呢,这里我们就需要使用我们自定义的scope,下面看看如果自定义一个scope:
import javax.inject.Scope
@Scope
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ExampleScope()
自定义scope的使用:
@ExampleScope
@Component(modules = [ExampleModule::class])
interface ExampleComponent {
fun inject(mainActivity: MainActivity)
}
@ExampleScope
@Provides
@Named("Woman")
fun providerWoman():Person{
return Woman()
}
只需要在相应的provider方法前面以及使用的component前面加上scope就可以了。需要注意的是一个component只能有一个scope。不然编译就会报错。