【发布时间】:2018-05-17 11:26:33
【问题描述】:
我是 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<UserEntity> 和RepoImpl<FruitEntity> 的后一个选项),我设法解决了对 RepoImpl 的依赖问题。我认为构造函数上的 @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: ..."
我还能如何注入这些接口的实现?
【问题讨论】:
-
假设类
Foo期望ApiService<BaseAttributes>被dagger 注入。并假设您提供的实现有效。当使用ApiService时,您期望会发生什么:它会使用UserService或FruitService作为实现吗?匕首不是为你做魔法。暂时假设,那把匕首不存在。您将提供哪个实现作为Foo类的参数? -
这取决于我需要哪个 RepoImpl 实例:
val userRepo = RepoImpl(UserService())或val fruitRepo = RepoImpl(FruitService())。我正在寻找的是 Dagger 等价物。我有一个 AppModule、UserModule 和 FruitModule,但不确定 @Provides 方法应该驻留在哪个模块中是否重要。我是一个十足的匕首菜鸟,所以请原谅我目前对此事的无知 -
It depends on which instance of RepoImpl I needed因此,目前您无法准确回答该问题,因为它取决于某些运行时类型。那么你如何期望 dagger 在编译时注入依赖呢?请参阅 dagger@Named注释用法,这可能就是您要搜索的内容。
标签: android dependency-injection kotlin dagger-2 dagger