Hilt中@Binds方法上的@Singleton在依赖注入时是否生效?
1. @Binds搭配@Singleton是否有效?
答案是:只有当实现类本身被Hilt以单例(或对应作用域)管理时,@Binds方法上的@Singleton才会生效。
@Binds的核心作用是绑定接口与实现类的映射关系,告诉Hilt:当需要TestInterface类型的实例时,返回TestInterfaceImpl的实例。而@Binds方法上的@Singleton注解,本质是要求Hilt在提供TestInterface类型实例时保证其为单例——但这个前提是,TestInterfaceImpl本身的实例是被Hilt单例化管理的。
在你的第一个场景中:
// 实现类无@Singleton注解 class TestInterfaceImpl @Inject constructor(): TestInterface{ override fun test(){} } // @Binds方法标注@Singleton @Module @InstallIn(SingletonComponent::class) object Module{ @Singleton @Binds fun providesImplementation(testImpl: TestInterfaceImpl): TestInterface }
由于TestInterfaceImpl没有作用域注解,Hilt每次需要创建它的实例时都会生成新对象,哪怕@Binds要求返回单例的TestInterface,底层的实现类实例还是新的,最终自然无法得到单例效果。
而当你给TestInterfaceImpl加上@Singleton后:
@Singleton class TestInterfaceImpl @Inject constructor(): TestInterface{ override fun test(){} }
此时TestInterfaceImpl本身被Hilt标记为单例,每次请求都会返回同一个实例,@Binds只是把这个单例实例映射为TestInterface类型,所以最终注入的就是单例。
2. Hilt是否应抛出不必要的警告?
是的,Hilt确实应该给出警告。
当@Binds方法上的作用域注解(比如@Singleton)无法生效时(比如实现类没有匹配的作用域),Hilt的编译检查应该提示开发者:当前@Binds的作用域注解无效,因为实现类的实例管理方式不支持该作用域。
Hilt的规则是:绑定的作用域必须与组件的作用域一致,且实现类的作用域不能比绑定的作用域更窄。如果实现类没有作用域,相当于每次都创建新实例,这时候@Binds的@Singleton就违背了组件的作用域约定,Hilt应该在编译阶段抛出错误或警告,提示开发者修复这个不匹配的问题。
内容的提问来源于stack exchange,提问作者Diken Mhrz

