Ker*_*rry 10 android kotlin dagger-hilt
我是 Hilt/Dagger 的新手,我还没有找到注入伴随对象的好例子。下面是我的单例和数据类。我正在尝试在 create() 函数中使用 TargetNumber 管理器。我正在寻找语法帮助和原因解释。
@InstallIn(SingletonComponent::class)
@Module
data class TargetNumberManager(
val maxNumber: Int = 3,
val prefix: String = "ZZ"
) : ITargetNumberManager {
private var currentNumber = 0
@Singleton
@Provides
override fun getNextTargetNumber(): String {
val targetNumberBuilder: StringBuilder = java.lang.StringBuilder()
targetNumberBuilder.append(prefix)
val lengthOfNumber = currentNumber.toString().length
for (i in lengthOfNumber..maxNumber step 1) {
targetNumberBuilder.append(0)
}
targetNumberBuilder.append(currentNumber++)
return targetNumberBuilder.toString()
}
}
Run Code Online (Sandbox Code Playgroud)
// 数据类
data class Target(
@PrimaryKey
val targetNumber: String,
val targetType: TargetType?,
val numOfElement: Int?,
val location: Coordinate?
) : java.io.Serializable {
@AndroidEntryPoint
companion object {
fun create(): Target {
@Inject var targetNumberManager : TargetNumberManager
val nextNumber = targetNumberManager.getNextTargetNumber()
return Target(nextNumber, null, null, null)
}
}
}
Run Code Online (Sandbox Code Playgroud)
看起来你想要的是要求 Dagger 创建一个对象的实例。让我解释一下如何使用EntryPoints 做到这一点。
在你的班级TargetNumberManager:
provides函数中使用变量(例如getNextTargetNumber),因为您提供的依赖项被标记为@Singleton:这意味着 Dagger 只会调用您的getNextTargetNumber()函数 1 次。最好将业务逻辑(例如计入管理器、用例等)和依赖项注入代码(例如向 Dagger 模块提供功能)分开。您可以将计数逻辑和 Dagger 模块分开,如下所示:
@Singleton
data class TargetNumberManager @Inject constructor(
val maxNumber: Int = 3,
val prefix: String = "ZZ"
) : ITargetNumberManager {
private var currentNumber = 0
override fun getNextTargetNumber(): String {
val targetNumberBuilder: StringBuilder = java.lang.StringBuilder()
targetNumberBuilder.append(prefix)
val lengthOfNumber = currentNumber.toString().length
for (i in lengthOfNumber..maxNumber step 1) {
targetNumberBuilder.append(0)
}
targetNumberBuilder.append(currentNumber++)
return targetNumberBuilder.toString()
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
@InstallIn(SingletonComponent::class)和@Module注释。这意味着这个类不再是一个模块。因为TargetNumberManager看起来像是业务逻辑的实现,并且与依赖注入无关。@Inject注释到 constructor . 这意味着 Dagger 将实例化这个类。为了让 Dagger 创建 的实例TargetNumberManager,它需要找到和变量TargetNumberManager的依赖关系。您也需要提供它们。maxNumberprefix现在我们可以将它们提取为常量:
@Singleton
data class TargetNumberManager @Inject constructor() : ITargetNumberManager {
private var currentNumber = 0
override fun getNextTargetNumber(): String {
val targetNumberBuilder: StringBuilder = java.lang.StringBuilder()
targetNumberBuilder.append(PREFIX)
val lengthOfNumber = currentNumber.toString().length
for (i in lengthOfNumber..MAX_NUMBER step 1) {
targetNumberBuilder.append(0)
}
targetNumberBuilder.append(currentNumber++)
return targetNumberBuilder.toString()
}
companion object {
private const val MAX_NUMBER: Int = 3
private const val PREFIX: String = "ZZ"
}
}
Run Code Online (Sandbox Code Playgroud)
通过这些更改,TargetNumberManagerDagger 可以在您想要将其注入某处时创建它。它被标记为 Singleton,因此只要您注入它,Dagger 就会提供相同的实例。
当您尝试注入ITargetNumberManager. 因为你有一个接口和一个实现,但是同一个接口可能还有其他实现,所以我们需要告诉 Dagger 使用哪一个。我们通过使用@Binds注释来做到这一点。@Binds方法必须是抽象的或位于接口内部。这里我为 Dagger 模块使用了抽象类:
@InstallIn(SingletonComponent::class)
@Module
abstract class MyModule {
@Binds
abstract fun bindTargetNumberManager(impl: TargetNumberManager): ITargetNumberManager
}
Run Code Online (Sandbox Code Playgroud)
现在,当您询问时,Dagger 知道要注入哪个实现ITargetNumberManager。请注意,我没有放在@Singleton这里,因为实现类TargetNumberManager已经标记为@Singleton. 因此,每当您注入类型TargetNumberManagerAND时,它都将是 Singleton ITargetNumberManager。
EntryPoint接口。Hilt发现这些接口并使组件接口扩展这些EntryPoint接口。使用 anEntryPoint基本上就像向组件接口添加功能一样。请参阅:https://dagger.dev/hilt/entry-pointsEntryPoint可以包含一个返回对象实例的函数。通过添加具有依赖项返回类型的函数,您只需要求 Dagger 为您创建一个实例即可。典型的 EntryPoint 如下所示:
@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyEntryPoint {
fun getTargetNumberManager(): ITargetNumberManager
}
Run Code Online (Sandbox Code Playgroud)
当您需要时ITargetNumberManager:获取此实例MyEntryPoint然后获取以下实例ITargetNumberManager:
val myEntryPoint: MyEntryPoint = EntryPoints.get(applicationContext, MyEntryPoint::class.java)
val targetNumberManager: ITargetNumberManager = myEntryPoint.getTargetNumberManager()
Run Code Online (Sandbox Code Playgroud)
就是这样!如果您想在课堂上这样做Target:
data class Target(
@PrimaryKey
val targetNumber: String,
val targetType: TargetType?,
val numOfElement: Int?,
val location: Coordinate?
) : java.io.Serializable {
companion object {
fun create(applicationContext: Context): Target {
val myEntryPoint: MyEntryPoint = EntryPoints.get(applicationContext, MyEntryPoint::class.java)
val targetNumberManager: ITargetNumberManager = myEntryPoint.getTargetNumberManager()
val nextNumber = targetNumberManager.getNextTargetNumber()
return Target(nextNumber, null, null, null)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Hilt 需要知道应用程序上下文,因为它将 SingletonComponent 保留在应用程序类中。所以它会去那里获取组件。获取组件后,它将转换为您的 EntryPoint 接口。然后您可以调用添加到 EntryPoint 中的函数。
AndroidEntryPoint仅适用于 Android 入口点,例如:Activity、Fragment、View、Service、BroadcastReceiver。不适用于伴生对象或其他类型的类。请参阅:https://dagger.dev/hilt/android-entry-point.html@Inject不能在函数内的变量中使用。您可以改为添加@Inject到构造函数中。我希望这有帮助。我试图解释每一点。如果您还有其他问题,请告诉我!
| 归档时间: |
|
| 查看次数: |
2573 次 |
| 最近记录: |