You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多模块Dagger项目问题:组件依赖多个作用域组件

解决多模块Android分层架构中Dagger 2跨模块注入的针对性方案

我太懂你这种困境了——分层多模块(Data、Domain、Presentation)的Android项目用Dagger 2,每个模块单独配Component但跨模块注入就是不work,之前搜的通用方案完全不管用。结合你的架构特点,我给你一套落地性极强的实现思路:

1. 先统一基础依赖配置

首先确保所有模块的Dagger依赖对齐,建议用项目根目录的Version Catalog(或者统一的build.gradle)管理版本,避免版本不一致:

// 根目录build.gradle的dependencyManagement块
dependencyManagement {
    dependencies {
        dependency 'com.google.dagger:dagger:2.51.1'
        dependency 'com.google.dagger:dagger-compiler:2.51.1'
        dependency 'com.google.dagger:dagger-android:2.51.1'
        dependency 'com.google.dagger:dagger-android-processor:2.51.1'
    }
}

每个模块的build.gradle里引入依赖并开启kapt:

plugins {
    id 'kotlin-kapt'
}

dependencies {
    implementation 'com.google.dagger:dagger'
    kapt 'com.google.dagger:dagger-compiler'
    // 若用到Android相关注入(比如Activity/Fragment注入)
    implementation 'com.google.dagger:dagger-android'
    kapt 'com.google.dagger:dagger-android-processor'
}

kapt {
    correctErrorTypes = true
}

2. 分层模块的Dagger组件设计

Domain层:做依赖契约的“中间枢纽”

Domain层是唯一的中立层,不依赖任何具体实现,只定义抽象的Component接口和依赖绑定契约,让Data和Presentation都依赖它,彻底解耦:

  • 定义DomainComponent,声明要向上/下层暴露的抽象依赖:
@Singleton
@Component(modules = [DomainBindings::class])
interface DomainComponent {
    // 给Presentation层暴露UseCase实例
    fun userUseCase(): UserUseCase
    // 给Data层暴露Repository抽象(如果需要Data层基于抽象实现)
    fun userRepository(): UserRepository

    // 工厂接口,方便其他组件创建依赖
    @Component.Factory
    interface Factory {
        fun create(@BindsInstance appContext: Context): DomainComponent
    }
}
  • 配套的DomainBindings模块,只放跨模块共享的抽象绑定:
@Module
abstract class DomainBindings {
    // 这里只绑定抽象,具体实现交给Data层
    @Binds
    abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
}

Data层:实现具体依赖并关联Domain组件

Data层依赖Domain层,创建DataModule提供具体的实现类,然后让Data的Component依赖DomainComponent:

@Module
class DataModule {
    @Provides
    @Singleton
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.yourdomain.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }

    @Provides
    @Singleton
    fun provideUserRepositoryImpl(api: ApiService): UserRepositoryImpl {
        return UserRepositoryImpl(api)
    }
}
@Singleton
@Component(
    dependencies = [DomainComponent::class],
    modules = [DataModule::class]
)
interface DataComponent {
    // 若需要向其他模块暴露Data层独有的依赖,在这里声明
    fun apiService(): ApiService

    @Component.Factory
    interface Factory {
        fun create(domainComponent: DomainComponent): DataComponent
    }
}

Presentation层:整合所有组件并注入UI

Presentation层依赖Domain层,创建PresentationModule提供UI相关依赖(比如ViewModel工厂),然后打造顶层的AppComponent整合所有子组件:

@Module
class PresentationModule {
    @Provides
    fun provideViewModelFactory(useCase: UserUseCase): MainViewModelFactory {
        return MainViewModelFactory(useCase)
    }
}
@Singleton
@Component(
    dependencies = [DomainComponent::class, DataComponent::class],
    modules = [PresentationModule::class, AndroidInjectionModule::class]
)
interface AppComponent : AndroidInjector<MyApp> {
    // 给Activity/Fragment提供注入入口
    fun inject(activity: MainActivity)

    @Component.Factory
    interface Factory : AndroidInjector.Factory<MyApp> {
        fun create(
            @BindsInstance appContext: Context,
            domainComponent: DomainComponent,
            dataComponent: DataComponent
        ): AppComponent
    }
}

3. 组件初始化与注入流程

在Application类里按顺序初始化组件,确保依赖链正确:

class MyApp : DaggerApplication() {
    private lateinit var domainComponent: DomainComponent
    private lateinit var dataComponent: DataComponent
    private lateinit var appComponent: AppComponent

    override fun onCreate() {
        super.onCreate()
        // 1. 先初始化最底层的DomainComponent
        domainComponent = DaggerDomainComponent.factory().create(applicationContext)
        // 2. 基于DomainComponent初始化DataComponent
        dataComponent = DaggerDataComponent.factory().create(domainComponent)
        // 3. 整合前两个组件初始化顶层AppComponent
        appComponent = DaggerAppComponent.factory().create(applicationContext, domainComponent, dataComponent)
        appComponent.inject(this)
    }

    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return appComponent
    }

    // 提供方法让UI层获取组件
    fun getAppComponent(): AppComponent = appComponent
}

4. 避坑关键提醒

  • 绝对禁止循环依赖:严格遵循Presentation → Domain ← Data的单向依赖,Data层绝对不能依赖Presentation层。
  • Singleton作用域统一:所有跨模块共享的依赖都用@Singleton,确保整个应用只有一个实例。
  • Subcomponent vs Dependencies:如果某个模块的组件只被顶层组件调用,用Subcomponent会更简洁;如果需要多个组件依赖它,用Dependencies方式更灵活。
  • Kapt缓存问题:如果遇到注入代码生成异常,先执行./gradlew clean build清理缓存。

之前的方案失效大概率是没处理好分层间的依赖契约——要么让模块直接互相依赖,要么没让Domain层承担枢纽角色,这套方案把Domain层做成抽象契约中心,彻底解决跨模块注入的耦合问题。

内容的提问来源于stack exchange,提问作者H.Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:58:54