Dagger2: scope的使用

146 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

image.png

所谓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@1a159c6I/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。不然编译就会报错。