我是Dagger的新手,并进行了以下设置:
// data models
open class BaseEntity (open val id: Long)
data class UserEntity (override val id: Long, val name: String) : BaseEntity(id)
data class FruitEntity (override val id: Long, val status: String) : BaseEntity(id)
// interface to spec common API response operations
interface Repo<T> {
fun getEntities(): List<T>
}
// entity specific implementation of the repo interface
class RepoImpl<T: BaseEntity> @Inject constructor(apiService: ApiService) : Repo<T> {
override fun getEntities(): List<T> {
val entities = apiService.getEntities(...)// get result from respective entity network service, e.g users, fruits etc
return entities
}
}
// DI: provide entity-specific implementations of the interface
@Singleton
@Provides
fun provideUserRepoImpl(userService: UserApiService): RepoImpl<BaseEntity> {
return RepoImpl(userService)
}
@Singleton
@Provides
fun provideFruitRepoImpl(fruitService: FruitApiService): RepoImpl<BaseEntity> {
return RepoImpl(fruitService)
}
当我构建项目时,会出现此错误:
error: RepoImpl<com.example.data.model.BaseEntity> is bound multiple times
...
@org.jetbrains.annotations.NotNull @Provides @Singleton com.example.data.source.remote.RepoImpl<com.example.data.model.BaseEntity> com.example.app.di.AppModule.provideUserRepoImpl()
@org.jetbrains.annotations.NotNull @Provides @Singleton com.example.data.source.remote.RepoImpl<com.example.data.model.BaseEntity> com.example.app.di.AppModule.provideFruitRepoImpl()
当我尝试提供特定于实体的实例时,如下所示:
@Singleton
@Provides
fun provideUserRepoImpl(userService: UserApiService): RepoImpl<UserEntity> {
return RepoImpl(userService)
}
@Singleton
@Provides
fun provideFruitRepoImpl(fruitService: FruitApiService): RepoImpl<FruitEntity> {
return RepoImpl(fruitService)
}
我得到以下内容:
error: RepoImpl<com.example.data.model.BaseEntity> cannot be provided without an @Inject constructor or from an @Provides-annotated method
我也试过分离水果的提供者方法。用户进入他们各自的模块,但后来的错误也出现了,也许我没有正确地连接FruitModule,UserModule和AppModule。我在提供接口实现方面遇到了类似的问题。
这里有什么正确的方法,或者根本不可能用Dagger注入参数化类?
更新
我已经设法通过显式提供要注入的每个对象来解决RepoImpl上的依赖性问题(后一个选项我们提供RepoImpl<UserEntity>
和RepoImpl<FruitEntity>
)。我认为构造函数上的@Inject注释在某种程度上没有被注册,
所以不得不刷新项目。
但是,我还无法弄清楚如何提供参数化接口的实现(或子类型)。 例如,考虑RepoImpl的ApiService参数定义如下:
// base service for all types of items
interface ApiService<T: BaseAttributes> {
fun getEntities(): T
}
// service impl for fruits
class FruitService : ApiService<FruitAttributes> {
override fun getEntities(): FruitResponses {...}
}
// service impl for users
class UserService : ApiService<UserAttributes> {
override fun getEntities(): UserResponses {...}
}
// AppModule.kt:
@Singleton
@Provides
fun provideUserService() : ApiService<UserAttributes> {
return UserService()
}
@Singleton
@Provides
fun provideFruitService() : ApiService<FruitAttributes> {
return FruitService()
}
错误:"... ApiService<BaseAttributes> cannot be provided without an @Provides-annotated method ..."
,而
...
fun provideUserService() : ApiService<BaseAttributes> {
return UserService() as ApiService<BaseAttributes>
}
...
fun provideFruitService() : ApiService<FruitAttributes> {
return FruitService() as ApiService<BaseAttributes>
}
错误:"... ApiService<BaseAttributes> is bound multiple times: ..."
我还能如何注入这些接口的实现?
答案 0 :(得分:1)
原来匕首/ kotlin仿制药上有一个well-discussed wildcard issue。特别是,参数化类中的“不能在没有@Annex-annotated方法”的情况下提供错误,需要在注入站点使用@JvmSuppressWildcard注释抑制通配符类型(协变量或逆变量)的生成。所以我会做的:
class RepoImpl<T: BaseEntity> @Inject constructor(apiService: @kotlin.jvm.JvmSuppressWildcards ApiService) : Repo<T> { ... }
虽然我实际上最终将RepoImpl
转换为抽象类并为Fruit&amp;创建具体的类。用户类型并在模块级提供它们:
class UserRepoImpl @Inject constructor(apiService: UserService) : RemoteRepoImpl(apiService)
class FruitRepoImpl @Inject constructor(apiService: FruitService) : RemoteRepoImpl(apiService)
此related SO question包含另一个示例。
最后,这个Kotlin+Dagger主题包含一些与此问题相关的好问题和提示