在 Dagger2 中使用 named 注入具有不同字段的相同 class 的两个对象
Inject two objects of the same class with different fields using named in Dagger2
假设我有矩形 class 实现形状接口
class Rectangle @Inject constructor(private val id: String) : Shape {
override fun info() {
Log.d("Rectangle", "I am rectangle!, My id is $id")
}
}
interface Shape {
fun info()
}
使用@Named 提供两个具有不同 id 的相同 class 对象的一种方法是在我的模块中:
@Module
class AppModule {
@Provides
@Named("Id1")
fun provideId1(): Shape {
return Rectangle("Id1")
}
@Provides
@Named("Id2")
fun provideId2(): Shape {
return Rectangle("Id2")
}
}
这样我就可以在我的 mainactivity 中注入两个矩形对象
@Inject
@field:Named("Id1")
lateinit var rect1: Shape
@Inject
@field:Named("Id2")
lateinit var rect2: Shape
但是我希望我的模块看起来有点不同。在其中,我想为对象提供形状和使用 @named 构造函数参数。我有的是:
@Module
class AppModule {
@Provides
@Named("Id1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("Id2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("id1")
fun provideId1(): String {
return "ABC"
}
@Provides
@Named("id2")
fun provideId2(): String {
return "XYZ"
}
}
如何使用这种方法实现注入两个具有不同构造函数参数的对象?
这是您遗漏的关键部分:
@Module
class AppModule {
@Provides
@Named("ShapeId1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("ShapeId2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
}
自动将提供的命名字符串放入实际矩形构造函数的部分。
不过,我会选择 simpler/cleaner 这样的东西:
RectangleNamed1Module.kt:
@Module(includes = [RectangleNamed1ProvidingModule::class])
internal interface RectangleNamed1Module {
@Binds
@Named("ShapeID1")
fun bindRectangle(rectangle: Rectangle): Shape
}
@Module
internal object RectangleNamed1ProvidingModule {
@Provides
fun provideRectangle(
@Named("id1") stringId: String
): Rectangle = Rectangle(stringId)
}
然后您可以...根据需要多次复制粘贴此模块,然后稍微更改命名 dependencies/parameters 仅此而已。
您可以将其用作 RectangleNamed1Module 和 RectangleNamed2Module,然后将这两个模块作为您的 AppModule 的依赖项。无论您尝试注入两个名为“Shape1”和“Shape2”的 shapes/rectangles 都应该有效,对吧?
根据我的评论,
Aha, i got it. I think. They can't be in the same module. The reason is: while the module is being processed, it will provide named strings, but they will not be in the graph to meet the criteria for providing the rectangle-providing methods with those named parameters. You will need to move string-providing methods to a different module, and make your AppModule use it as a dependency. Then it should work. However, this is just a best-effort guess
尝试这样的事情:
@Module(include = StringProvidingModule::class)
class AppModule {
@Provides
@Named("Id1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("Id2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
}
@Module
class StringProvidingModule {
@Provides
@Named("id1")
fun provideId1(): String {
return "ABC"
}
@Provides
@Named("id2")
fun provideId2(): String {
return "XYZ"
}
}
假设我有矩形 class 实现形状接口
class Rectangle @Inject constructor(private val id: String) : Shape {
override fun info() {
Log.d("Rectangle", "I am rectangle!, My id is $id")
}
}
interface Shape {
fun info()
}
使用@Named 提供两个具有不同 id 的相同 class 对象的一种方法是在我的模块中:
@Module
class AppModule {
@Provides
@Named("Id1")
fun provideId1(): Shape {
return Rectangle("Id1")
}
@Provides
@Named("Id2")
fun provideId2(): Shape {
return Rectangle("Id2")
}
}
这样我就可以在我的 mainactivity 中注入两个矩形对象
@Inject
@field:Named("Id1")
lateinit var rect1: Shape
@Inject
@field:Named("Id2")
lateinit var rect2: Shape
但是我希望我的模块看起来有点不同。在其中,我想为对象提供形状和使用 @named 构造函数参数。我有的是:
@Module
class AppModule {
@Provides
@Named("Id1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("Id2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("id1")
fun provideId1(): String {
return "ABC"
}
@Provides
@Named("id2")
fun provideId2(): String {
return "XYZ"
}
}
如何使用这种方法实现注入两个具有不同构造函数参数的对象?
这是您遗漏的关键部分:
@Module
class AppModule {
@Provides
@Named("ShapeId1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("ShapeId2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
}
自动将提供的命名字符串放入实际矩形构造函数的部分。
不过,我会选择 simpler/cleaner 这样的东西:
RectangleNamed1Module.kt:
@Module(includes = [RectangleNamed1ProvidingModule::class])
internal interface RectangleNamed1Module {
@Binds
@Named("ShapeID1")
fun bindRectangle(rectangle: Rectangle): Shape
}
@Module
internal object RectangleNamed1ProvidingModule {
@Provides
fun provideRectangle(
@Named("id1") stringId: String
): Rectangle = Rectangle(stringId)
}
然后您可以...根据需要多次复制粘贴此模块,然后稍微更改命名 dependencies/parameters 仅此而已。
您可以将其用作 RectangleNamed1Module 和 RectangleNamed2Module,然后将这两个模块作为您的 AppModule 的依赖项。无论您尝试注入两个名为“Shape1”和“Shape2”的 shapes/rectangles 都应该有效,对吧?
根据我的评论,
Aha, i got it. I think. They can't be in the same module. The reason is: while the module is being processed, it will provide named strings, but they will not be in the graph to meet the criteria for providing the rectangle-providing methods with those named parameters. You will need to move string-providing methods to a different module, and make your AppModule use it as a dependency. Then it should work. However, this is just a best-effort guess
尝试这样的事情:
@Module(include = StringProvidingModule::class)
class AppModule {
@Provides
@Named("Id1")
fun provideId1(@Named("id1") id: String): Shape {
return Rectangle(id)
}
@Provides
@Named("Id2")
fun provideId2(@Named("id2") id: String): Shape {
return Rectangle(id)
}
}
@Module
class StringProvidingModule {
@Provides
@Named("id1")
fun provideId1(): String {
return "ABC"
}
@Provides
@Named("id2")
fun provideId2(): String {
return "XYZ"
}
}