如何使用 Hilt 注入 Map
How to inject a Map using Hilt
我有这样的设置:
interface Animal {
}
class Dog @Inject constructor() : Animal
class AnimalProxy @Inject constructor(
val animalFactory: AnimalFactory,
val animalMap: Map<AnimalType, Animal>
) : Animal
enum class AnimalType {
Pet,
Wild
}
class AnimalFactory @Inject constructor ()
这就是我在模块中绑定这些对象的方式
@Module
@InstallIn(SingletonComponent::class)
class AnimalModule {
@MapKey
annotation class AnimalTypeKey(val value: AnimalType)
@Named(DOG)
@Provides
fun provideDog(
): Animal {
return Dog()
}
@Provides
@Singleton
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
@Named(PROXY)
fun provideAnimalProxy(
animalProxy: AnimalProxy
) : Animal = animalProxy
companion object {
const val DOG = "dog"
const val PROXY = "proxy"
}
}
但不知何故有些事情不太对劲,我无法弄清楚发生了什么。我收到一个错误 cannot be provided without an @provides-annotated method
。我在创建 provideAnimalProxy
时知道出了点问题,但无法弄清楚。我的其他工作选项是:
@InstallIn(SingletonComponent::class)
@Module
class AnimalsModule {
@Singleton
@Provides
fun provideProxy(
): Animal {
return AnimalProxy(
AnimalFactory(),
mapOf(
AnimalType.Pet to Dog(),
),
)
}
}
但是对于 AnimalFactory
我已经有了一个 inject
构造函数。
@Named(DOG)
@Provides
fun provideDog(
): Animal { // Provides @Named(DOG) Animal
return Dog() // which will return a Dog()
}
@Provides
@Singleton
@IntoMap
@AnimalTypeKey(AnimalType.Pet) // Binds the key Pet
@Named(PROXY) // into @Named(PROXY) Map<AnimalType, Animal>
fun provideAnimalProxy(
animalProxy: AnimalProxy
) : Animal = animalProxy // which will return an AnimalProxy()
听起来您想要的是使用其 @Inject
构造函数在地图外部绑定 AnimalProxy。看起来像这样:
@Provides
@IntoMap // @IntoMap here means Map<key, Animal>
// because the function returns Animal
@AnimalTypeKey(AnimalType.Pet) // @AnimalTypeKey(Pet) means the key is Pet
// Nothing is @Named, so the map isn't named
fun provideDog(
): Animal { // Binds Pet into Map<AnimalType, Animal>
return Dog() // which will return a Dog()
}
或者,由于 Dog 有一个 @Inject
带注释的构造函数,您可以简化为:
@Provides
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
fun provideDog(dog: Dog): Animal = dog
或与,抽象class或接口:
@Binds
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
abstract fun bindDog(dog: Dog): Animal
对于 AnimalProxy,您不应该对要注入的对象使用 @Provides
方法;如果你想要 @Singleton
,你可以注释 AnimalProxy class 本身。您可以完全删除模块的那部分。
但是,您可能希望 AnimalProxy 出现在 Map<AnimalType, Animal>
本身中,这听起来像是一个循环引用:要创建地图,您需要创建每个动物,包括代理,这需要创建您当前正在尝试创建的相同地图。如果是这种情况,您确实有一个解决方法:您可以 automatically inject a Map<AnimalType, Provider<Animal>>
the same way you can inject a Provider<Dog>
rather than just a Dog
而不是注入 Map<AnimalType, Animal>
。这样你就不会在构造函数中表达对真正的 AnimalProxy(或其 Map)的需求,这样 Dagger 就不会抱怨了。
我有这样的设置:
interface Animal {
}
class Dog @Inject constructor() : Animal
class AnimalProxy @Inject constructor(
val animalFactory: AnimalFactory,
val animalMap: Map<AnimalType, Animal>
) : Animal
enum class AnimalType {
Pet,
Wild
}
class AnimalFactory @Inject constructor ()
这就是我在模块中绑定这些对象的方式
@Module
@InstallIn(SingletonComponent::class)
class AnimalModule {
@MapKey
annotation class AnimalTypeKey(val value: AnimalType)
@Named(DOG)
@Provides
fun provideDog(
): Animal {
return Dog()
}
@Provides
@Singleton
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
@Named(PROXY)
fun provideAnimalProxy(
animalProxy: AnimalProxy
) : Animal = animalProxy
companion object {
const val DOG = "dog"
const val PROXY = "proxy"
}
}
但不知何故有些事情不太对劲,我无法弄清楚发生了什么。我收到一个错误 cannot be provided without an @provides-annotated method
。我在创建 provideAnimalProxy
时知道出了点问题,但无法弄清楚。我的其他工作选项是:
@InstallIn(SingletonComponent::class)
@Module
class AnimalsModule {
@Singleton
@Provides
fun provideProxy(
): Animal {
return AnimalProxy(
AnimalFactory(),
mapOf(
AnimalType.Pet to Dog(),
),
)
}
}
但是对于 AnimalFactory
我已经有了一个 inject
构造函数。
@Named(DOG)
@Provides
fun provideDog(
): Animal { // Provides @Named(DOG) Animal
return Dog() // which will return a Dog()
}
@Provides
@Singleton
@IntoMap
@AnimalTypeKey(AnimalType.Pet) // Binds the key Pet
@Named(PROXY) // into @Named(PROXY) Map<AnimalType, Animal>
fun provideAnimalProxy(
animalProxy: AnimalProxy
) : Animal = animalProxy // which will return an AnimalProxy()
听起来您想要的是使用其 @Inject
构造函数在地图外部绑定 AnimalProxy。看起来像这样:
@Provides
@IntoMap // @IntoMap here means Map<key, Animal>
// because the function returns Animal
@AnimalTypeKey(AnimalType.Pet) // @AnimalTypeKey(Pet) means the key is Pet
// Nothing is @Named, so the map isn't named
fun provideDog(
): Animal { // Binds Pet into Map<AnimalType, Animal>
return Dog() // which will return a Dog()
}
或者,由于 Dog 有一个 @Inject
带注释的构造函数,您可以简化为:
@Provides
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
fun provideDog(dog: Dog): Animal = dog
或与
@Binds
@IntoMap
@AnimalTypeKey(AnimalType.Pet)
abstract fun bindDog(dog: Dog): Animal
对于 AnimalProxy,您不应该对要注入的对象使用 @Provides
方法;如果你想要 @Singleton
,你可以注释 AnimalProxy class 本身。您可以完全删除模块的那部分。
但是,您可能希望 AnimalProxy 出现在 Map<AnimalType, Animal>
本身中,这听起来像是一个循环引用:要创建地图,您需要创建每个动物,包括代理,这需要创建您当前正在尝试创建的相同地图。如果是这种情况,您确实有一个解决方法:您可以 automatically inject a Map<AnimalType, Provider<Animal>>
the same way you can inject a Provider<Dog>
rather than just a Dog
而不是注入 Map<AnimalType, Animal>
。这样你就不会在构造函数中表达对真正的 AnimalProxy(或其 Map)的需求,这样 Dagger 就不会抱怨了。