Android HILT SingletonComponent 与 GoF Singleton 实例设计模式
Android HILT SingletonComponent vs the GoF Singleton instance design pattern
在一个Android项目中,有一个作为单例实现的外观。我认为使用 HILT SingletonComponent 将其转换为 DI 是一个更好的主意。
@Module
@InstallIn(SingletonComponent::class)
object MyManagerModule {
@Provides
fun provide(@ApplicationContext context: Context): MyManager {
return MyManager(context)
}
}
class MyManager @Inject constructor(@ApplicationContext private val ctx: Context){
//
}
从几个调用者那里,我使用 HILT 字段注入获得了上述 MyManager 的实例,即
@AndroidEntryPoint
class MyCallerFragment : Fragment() {
@Inject lateinit var myManager: MyManager
// ...
在调试器中,我观察到 DI 实例实际上 不是 相同的实例(假设这些片段处于相同的 activity 生命周期中)。我想我一定是误解了 Hilt DI :-( 如果你看到我的盲点,我很乐意听到任何解释。
TL;DR
您需要使用注解@Singleton
。这将告诉 Hilt 在整个应用程序中使用同一个 MyManager 实例。
绑定范围
By default, all bindings in Hilt are unscoped. This means that each time your app requests the binding, Hilt creates a new instance of the needed type.
和
However, Hilt also allows a binding to be scoped to a particular component. Hilt only creates a scoped binding once per instance of the component that the binding is scoped to, and all requests for that binding share the same instance.
@Singleton
注释将您的 Hilt 绑定范围限定为应用程序组件。 (包括所有子项,它们都是组件)因此 Hilt 将在整个应用中注入对象的相同实例。
Google 在 this guide 中有一个例子。
@InstallIn
注解
注释 @InstallIn()
告诉 Hilt MyManager 对象将被注入到哪个组件中。
在您 @InstallIn(SingletonComponent::class)
的情况下,Hilt 将使 MyManager 可用于在应用程序组件和该组件的所有子组件中注入,但这并不意味着 Hilt 将提供相同的实例。由于任何默认组件都是应用程序组件的子组件,因此 MyManager 目前可以访问以注入到任何组件中。 (根据the documentation)
我有类似的问题,Hilt 中的范围与组件,这就是我得到的:
当你用 @InstalIn
注释 class 时,实际上你是在定义这个依赖模块的生命周期。例如,如果您使用 SingletonComponent
,只要应用程序启动,来自此 class(模块)的所有依赖项都会保留。
对于 Scope,当您在模块中提供依赖项时,每次调用该模块时,都会创建一个新实例。这就是为什么您在调试器中观察到生成的实例不一样。通过像 @Singleton
一样使用 Scopes
,您正在改变 dagger-hilt 在调用依赖项上的实例化方式。
所以一般来说,Component 是生命周期,Scope 是每次调用依赖实例化的方式。
不要错过这篇文章:
https://medium.com/digigeek/hilt-components-and-scopes-in-android-b96546cb07df
在一个Android项目中,有一个作为单例实现的外观。我认为使用 HILT SingletonComponent 将其转换为 DI 是一个更好的主意。
@Module
@InstallIn(SingletonComponent::class)
object MyManagerModule {
@Provides
fun provide(@ApplicationContext context: Context): MyManager {
return MyManager(context)
}
}
class MyManager @Inject constructor(@ApplicationContext private val ctx: Context){
//
}
从几个调用者那里,我使用 HILT 字段注入获得了上述 MyManager 的实例,即
@AndroidEntryPoint
class MyCallerFragment : Fragment() {
@Inject lateinit var myManager: MyManager
// ...
在调试器中,我观察到 DI 实例实际上 不是 相同的实例(假设这些片段处于相同的 activity 生命周期中)。我想我一定是误解了 Hilt DI :-( 如果你看到我的盲点,我很乐意听到任何解释。
TL;DR
您需要使用注解@Singleton
。这将告诉 Hilt 在整个应用程序中使用同一个 MyManager 实例。
绑定范围
By default, all bindings in Hilt are unscoped. This means that each time your app requests the binding, Hilt creates a new instance of the needed type.
和
However, Hilt also allows a binding to be scoped to a particular component. Hilt only creates a scoped binding once per instance of the component that the binding is scoped to, and all requests for that binding share the same instance.
@Singleton
注释将您的 Hilt 绑定范围限定为应用程序组件。 (包括所有子项,它们都是组件)因此 Hilt 将在整个应用中注入对象的相同实例。
Google 在 this guide 中有一个例子。
@InstallIn
注解
注释 @InstallIn()
告诉 Hilt MyManager 对象将被注入到哪个组件中。
在您 @InstallIn(SingletonComponent::class)
的情况下,Hilt 将使 MyManager 可用于在应用程序组件和该组件的所有子组件中注入,但这并不意味着 Hilt 将提供相同的实例。由于任何默认组件都是应用程序组件的子组件,因此 MyManager 目前可以访问以注入到任何组件中。 (根据the documentation)
我有类似的问题,Hilt 中的范围与组件,这就是我得到的:
当你用 @InstalIn
注释 class 时,实际上你是在定义这个依赖模块的生命周期。例如,如果您使用 SingletonComponent
,只要应用程序启动,来自此 class(模块)的所有依赖项都会保留。
对于 Scope,当您在模块中提供依赖项时,每次调用该模块时,都会创建一个新实例。这就是为什么您在调试器中观察到生成的实例不一样。通过像 @Singleton
一样使用 Scopes
,您正在改变 dagger-hilt 在调用依赖项上的实例化方式。
所以一般来说,Component 是生命周期,Scope 是每次调用依赖实例化的方式。
不要错过这篇文章: https://medium.com/digigeek/hilt-components-and-scopes-in-android-b96546cb07df