多数据库App的Dagger2注入异常:DataSource无法注入Database
看起来你遇到的是Dagger子组件依赖范围不匹配的编译错误。让我帮你拆解一下问题原因,然后给出具体的修复步骤:
问题根源
你的报错java.lang.IllegalArgumentException: no expression found for BindingRequest{key=com.xxxxx.app.framework.database.Database...}本质是:Dagger在编译时发现某个组件需要Database依赖,但该组件无法访问到Database的提供者。
具体来说:
- 你在
LoggedInComponent(子组件)的DatabaseModule中提供了Database实例,但ApplicationComponent(根组件)的模块列表里包含了FragmentBuilder,而FragmentBuilder中的ReportFragment依赖了ReportModule→UseCaseModule→RepositoryModule→DataSourceModule这条链,最终ReportSheetDatabaseImpl需要注入Database。 - 当Dagger为
ApplicationComponent生成代码时,它会尝试处理ReportFragment的注入逻辑,但ApplicationComponent并没有提供Database的能力(Database只在LoggedInComponent里提供),所以编译失败。 - 而直接在
ReportViewModel中注入Database时能成功,是因为这个ViewModel仅在LoggedInComponent管辖的Activity/Fragment中被使用,Dagger不需要为ApplicationComponent生成该ViewModel的注入代码,因此不会触发错误。
修复步骤
1. 调整根组件的模块范围
把FragmentBuilder从ApplicationComponent的模块列表中移除,确保只有LoggedInComponent管辖的Activity才能加载依赖Database的Fragment:
@ApplicationScope @Component( modules = [ AndroidSupportInjectionModule::class, AndroidInjectionModule::class, ApplicationModule::class, ActivityBuilder::class // 移除 FragmentBuilder::class,它只在LoggedInActivityBuilder中保留 ] ) interface ApplicationComponent : AndroidInjector<Altagem> { // ... 其余代码保持不变 }
2. 确保依赖链完全归属子组件管辖
确认所有依赖Database的模块(DataSourceModule、RepositoryModule、UseCaseModule、ReportModule)仅被包含在LoggedInComponent的注入链中:
- 你的
LoggedInActivityBuilder已经包含了FragmentBuilder,而ReportFragment的ContributesAndroidInjector引用了ReportModule,这条链路是正确的,无需额外修改。 - 如果有其他非
LoggedIn的Activity/Fragment也引用了这些模块,需要将它们拆分出来,避免跨范围依赖。
3. (可选)明确ViewModel的注入范围
为了避免ViewModel的依赖范围混淆,建议在ReportModule中添加ViewModel的绑定,确保它仅在LoggedInComponent的范围内被提供:
@Module abstract class ReportModule { // 原有的其他绑定代码... @Binds @IntoMap @ViewModelKey(ReportViewModel::class) abstract fun bindReportViewModel(viewModel: ReportViewModel): ViewModel }
同时确保你的项目中已经配置了Dagger的ViewModel工厂(比如DaggerViewModelFactory),让ViewModel从所属的Activity/Fragment组件中获取依赖。
验证修复
完成上述修改后,重新运行Gradle构建:
./gradlew clean build
此时Dagger会只为LoggedInComponent管辖的组件处理Database依赖,而ApplicationComponent不再需要处理这些依赖,编译错误应该会消失。
内容的提问来源于stack exchange,提问作者Houssem Ezzine

