在前面的文章,我们介绍了依赖注入及作用域的使用,这一小节我们来介绍一下提高篇中最后一小节《限定符》。前面文章如下:
【Kotlin中使用Dagger2】基础入门篇(一)
【Kotlin中使用Dagger2】基础入门篇(二)
【Kotlin中使用Dagger2】进阶提升篇(一)
【Kotlin中使用Dagger2】进阶提升篇(二)
- Qualifier-限定符
- @Named
- 自定义限定符
Qualifier-限定符
经过之前我们的介绍,Dagger2可以入注入普通类、接口及第三方类等,如果在注入接口时,它有多个不同的实现类,Dagger2如何选择使用哪一个实现类来实例化?
首先,我们引入一段完成代码(基于前面的代码封装),看一下这种情况是如何发生的。
/*
业务级Component
*/
@PerModelScope
@Component(dependencies = [ActivityComponent::class],modules = [(AnimalModule::class)])
interface AnimalComponent {
fun inject(activity:AnimalActivity)
}
/*
业务级Module
*/
@Module
class AnimalModule {
@Provides
fun provideCatService(service: CatServiceImpl):AnimalService{
return service
}
@Provides
fun provideDogService(service: DogServiceImpl):AnimalService{
return service
}
}
/*
动物 接口
*/
interface AnimalService {
fun eat()
}
/*
动物"猫" 实现类
*/
class CatServiceImpl @Inject constructor():AnimalService{
override fun eat() {
d("eat","Cat")
}
}
/*
动物"狗" 实现类
*/
class DogServiceImpl @Inject constructor():AnimalService{
override fun eat() {
d("eat","Dog")
}
}
/*
Actvity
*/
class AnimalActivity : BaseActivity() {
@Inject
lateinit var mCatService:AnimalService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_animal)
initInjection()
mCatService.eat()
}
/*
Dagger2注入注册
*/
private fun initInjection() {
DaggerAnimalComponent.builder().activityComponent(mActivityComponent).animalModule(AnimalModule()).build().inject(this)
}
}
大家可以看到,接口“ AnimalService”有两个实现类:CatServiceImpl和DogServiceImpl,并且我们在AnimalModule中提供了两个实例化方法,返回结果都是接口AnimalService。
接下来,在AnimalActivity中,我们使用Dagger2注入了一个AnimalService的实例,很遗憾的告诉大家,编译报错。因为Dagger2不知道使用哪个实现类来实例化(CatServiceImpl和DogServiceImpl),我们称这种情况为“注入迷失”。
如何解决这样的问题,Dagger2提供了限定符的概念(本身是Java提供的),使用注解@Qualifier可以声明一个限定符注解(同@Scope,用来声明注解的注解),使用限定符注解就可以标明具体使用哪一个实现类来进行实例化。
@Named在Scope中,存在默认实现@Singleton;在Qualifier,同样存在具体的实现@Named。我们先看一下它的源码:
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}
可以看到,@Named是可以带参数的,它的默认值是""。如何使用它来区别具体的实现类?我们需要修改Moduel,代码如下:
/*
业务级Module
*/
@Module
class AnimalModule {
@Named(value ="cat" )
@Provides
fun provideCatService(service: CatServiceImpl):AnimalService{
return service
}
@Named(value = "dog")
@Provides
fun provideDogService(service: DogServiceImpl):AnimalService{
return service
}
}
我们在工厂方法上使用@Named,给不同的实现添加一个“名称”,一个是"cat”,另一个是“dog"。为了在使用的时候让它根据”名称“来进行不同的实例化。我们还需要在调用层(Activity)声明时加上”名称“区别一下。代码如下:
@field:[Named ("cat")]
@Inject
lateinit var mCatService:AnimalService
和之前相比,多了一行"@field:[Named ("cat")]”,使用"cat"来进行实例化当前这个变量。
请注意: 这是Kotlin中的写法,在Java中直接使用@Named("cat")。具体可参考《Kotlin中使用@Named》
同样,我们可以把另外一个实现类也实例化出来,完整调用代码:
/*
Actvity
*/
class AnimalActivity : BaseActivity() {
@field:[Named ("cat")]
@Inject
lateinit var mCatService:AnimalService
@field:[Named ("dog")]
@Inject
lateinit var mDogService:AnimalService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_animal)
initInjection()
mCatService.eat()
mDogService.eat()
}
/*
Dagger2注入注册
*/
private fun initInjection() {
DaggerAnimalComponent.builder().activityComponent(mActivityComponent).animalModule(AnimalModule()).build().inject(this)
}
}
这样的话,我们就有效的区分了一个接口多个实现类的不同实例化。
自定义限定符除了使用@Named来进行区别以外,我们也可以自定义限定符来进行区别。自定义的方式和之前自定义Scope类似,使用@Named的源码改一下就行啦。
我们这里就直接自定义两个限定符,一个用来标识”cat",一个用来标识"dog“。代码如下:
/*
Cat 限定符
*/
@Qualifier
@Documented
@Retention(RUNTIME)
annotation class CatQualifier
/*
Dog 限定符
*/
@Qualifier
@Documented
@Retention(RUNTIME)
annotation class DogQualifier
和@Named不同的是,我们没有使用参数,是否需要参数,大家根据实际情况修改即可。
如何使用自定义限定符,同@Named类似,首先需要修改Module:
/*
业务级Module
*/
@Module
class AnimalModule {
@CatQualifier
@Provides
fun provideCatService(service: CatServiceImpl):AnimalService{
return service
}
@DogQualifier
@Provides
fun provideDogService(service: DogServiceImpl):AnimalService{
return service
}
}
接下来需要修改调用层声明:
@field:[CatQualifier]
@Inject
lateinit var mCatService:AnimalService
@field:[DogQualifier]
@Inject
lateinit var mDogService:AnimalService
是不是和@Named很像,只是换成了自定义的限定符,并且没有参数。
请注意,在Java中,是直接使用@CatQualifier和@DogQualifier进行标注。
小结这一小节我们介绍了限定符的使用及如何自定义限定符,用来解决“注入迷失”的情况。
大家在开发过程中,可以根据实际情况,使用@Named或者自定义限定符。
更多精彩应用《Kotlin打造完整电商APP》
热门评论
好,是真的好,买雷宇老师的课真的是物超所值