Hilt自定义作用域对象添加Lazy Provider包装报错的解决方法
解决Hilt自定义作用域中Provider注入的MissingBinding错误
问题场景
在基于Hilt的自定义作用域项目中,尝试给CustomComponent.Builder添加Provider包装实现懒加载时,触发以下Dagger绑定错误:
[Dagger/MissingBinding] dagger.internal.Provider<com.example.testcustomscopes.TestService> cannot be provided without an @Provides-annotated method. public abstract static class SingletonC implements MyApplication_GeneratedInjector,
现有可运行的基础代码如下:
interface TestService { fun doSomething(): String } @CustomScope class TestServiceImpl @Inject constructor() : TestService { override fun doSomething(): String { return "TestServiceImpl" } } @Module @InstallIn(CustomComponent::class) object AppModule { @CustomScope @Provides fun provideScopedClass(): TestService { return TestServiceImpl() } } @Scope @Retention(AnnotationRetention.RUNTIME) annotation class CustomScope @CustomScope @DefineComponent(parent = SingletonComponent::class) interface CustomComponent { @DefineComponent.Builder interface Builder { fun build(): CustomComponent } } @InstallIn(CustomComponent::class) @EntryPoint interface CustomEntryPoint { fun getCustomDependency(): TestService } @Singleton class CustomComponentManager @Inject constructor( private val customComponentBuilder: CustomComponent.Builder ) { private var customComponent: CustomComponent? = null fun createComponent() { customComponent = customComponentBuilder.build() } fun getComponent(): CustomComponent? { return customComponent } fun clearComponent() { customComponent = null } } @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject lateinit var customComponentManager: CustomComponentManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() var customDependency: TestService? = null val customComponent = customComponentManager.getComponent() if (customComponent != null) { val entryPoint = EntryPoints.get(customComponent, CustomEntryPoint::class.java) customDependency = entryPoint.getCustomDependency() println(customDependency.doSomething()) } }
问题原因
Dagger Hilt不允许跨作用域直接请求子作用域对象的Provider实例:CustomComponentManager属于Singleton作用域,而TestService绑定在子作用域CustomComponent下,直接在父作用域中尝试获取子作用域对象的Provider会导致绑定缺失。同时,直接注入Provider<CustomComponent.Builder>不符合Hilt管理子组件创建的规范。
解决方案
1. 用ComponentFactory替代Provider<CustomComponent.Builder>
Hilt提供ComponentFactory来规范子组件的创建,这是获取子组件Builder的标准方式,替换CustomComponentManager的注入参数:
@Singleton class CustomComponentManager @Inject constructor( private val customComponentFactory: ComponentFactory<CustomComponent.Builder> ) { private var customComponent: CustomComponent? = null fun createComponent() { customComponent = customComponentFactory.create().build() } fun getComponent(): CustomComponent? { return customComponent } fun clearComponent() { customComponent = null } }
2. 按需为TestService添加懒加载(可选)
如果需要延迟TestService的实例化,修改CustomEntryPoint返回Provider<TestService>:
@InstallIn(CustomComponent::class) @EntryPoint interface CustomEntryPoint { fun getCustomDependency(): Provider<TestService> }
使用时按需获取实例:
val customComponent = customComponentManager.getComponent() if (customComponent != null) { val entryPoint = EntryPoints.get(customComponent, CustomEntryPoint::class.java) val testServiceProvider = entryPoint.getCustomDependency() // 需要时才创建实例 val customDependency = testServiceProvider.get() println(customDependency.doSomething()) }
3. 移除冗余的Provider方法(优化)
TestServiceImpl已经有@Inject构造函数,AppModule中的provideScopedClass方法属于冗余代码,可以直接删除,Hilt会自动通过构造函数注入TestServiceImpl:
@Module @InstallIn(CustomComponent::class) object AppModule { // 移除provideScopedClass方法 }
内容的提问来源于stack exchange,提问作者Rowan Gontier
相关产品推荐
相关产品推荐

