以下是关于Android中Dagger2的详细解析,结合其核心原理、使用场景及最佳实践:
一、Dagger2核心概念
Dagger2是Google维护的依赖注入(DI)框架,通过编译时注解处理生成代码,实现依赖关系的自动化管理。其核心目标是通过解耦组件提升代码可维护性和可测试性。
1. 依赖注入(DI)的核心思想
-
控制反转(IoC):对象的创建权由外部容器管理,而非类自身。
-
依赖解耦:类不直接实例化依赖对象,而是通过接口或抽象类声明需求。
-
可测试性:依赖可替换为Mock对象,便于单元测试。
2. 核心注解
| 注解 | 作用 | 示例场景 |
|---|---|---|
|
| 标记需要注入的字段、构造函数或方法 | 字段注入、构造函数注入 |
|
| 标记提供依赖的类(无法通过 | 第三方库对象、复杂对象创建 |
|
| 标记Module中提供依赖的方法 | 定义 |
|
| 连接Module与注入目标的桥梁,生成依赖注入代码 | 定义全局或局部依赖容器 |
|
| 定义依赖生命周期(如 | 控制 |
|
| 区分相同类型的不同依赖实例 | 多个 |
3 设计思路

| 角色 | 职责 | 生命周期 |
|---|---|---|
| Module | 提供依赖实例的创建逻辑(通过 | 与 Component 绑定,随 Component 生命周期结束销毁 |
| Component | 依赖注入的入口,连接 Module 和目标类(如 Activity),管理依赖的创建与注入 | 由 Application 或子 Component 控制生命周期 |
| Activity | 被注入的目标类,通过 | Android 生命周期决定其存在时间 |
二、Dagger2使用流程
1. 添加依赖
// app/build.gradle
dependencies {
implementation 'com.google.dagger:dagger:2.41'
kapt 'com.google.dagger:dagger-compiler:2.41' // Kotlin需使用kapt
}
2. 定义依赖提供者(Module)
@Module
class AppModule {
@Provides
@Singleton
fun provideApiService(): ApiService {
return Retrofit.Builder()
.baseUrl("https://api.example.com")
.build()
.create(ApiService::class.java)
}
}
3. 创建依赖容器(Component)
@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
}
4. 注入依赖
class MainActivity : AppCompatActivity() {
@Inject
lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
(application as MyApp).appComponent.inject(this)
apiService.fetchData()
}
}
三、Dagger2核心原理
1. 编译时代码生成
-
APT(Annotation Processing Tool):在编译阶段扫描注解,生成辅助类(如
DaggerAppComponent)。 -
生成的类结构:
-
DaggerXXXComponent:实现Component接口,管理依赖图。 -
XXXModule_ProvidesXXXFactory:生成依赖实例的工厂类。 -
XXX_MembersInjector:注入依赖到目标类。
-
2. 依赖解析流程
-
标记注入点:通过
@Inject声明需要注入的字段或构造函数。 -
构建依赖图:Component根据Module的
@Provides方法和构造函数递归解析依赖。 -
生成注入代码:APT生成代码完成依赖实例的创建和赋值。
四、高级特性
1. 作用域管理
-
@Singleton:全局单例(需在Module和Component均标注)。 -
自定义作用域:
@Scope @Retention(AnnotationRetention.RUNTIME) annotation class ActivityScope @ActivityScope @Component(modules = [ActivityModule::class]) interface ActivityComponent
2. 多模块与子组件
-
多模块注入:通过多个
@Module组合提供依赖。@Component(modules = [NetworkModule::class, DatabaseModule::class]) interface AppComponent -
子组件(Subcomponent):继承父组件依赖,管理局部生命周期(如Activity级单例)。
@Subcomponent(modules = [ActivityModule::class]) interface ActivityComponent { @Subcomponent.Builder abstract class Builder : AndroidInjector.Builder<Activity>() }
3. 依赖冲突解决
-
@Named注解:区分相同类型的不同实例。@Provides @Named("api") fun provideApiUrl(): String = "https://api.example.com" @Provides @Named("web") fun provideWebUrl(): String = "https://www.example.com" -
自定义
@Qualifier:@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class ApiUrl @Provides @ApiUrl fun provideApiUrl(): String = "https://api.example.com"
五、实际应用场景
1. MVP架构解耦
-
Presenter注入:通过Component将Presenter注入Activity/Fragment。
class LoginPresenter @Inject constructor( private val view: LoginView, private val repository: UserRepository ) { ... }
2. 第三方库集成
-
Retrofit/Room实例:在Module中提供,避免硬编码。
@Module class NetworkModule { @Provides fun provideRetrofit(): Retrofit { return Retrofit.Builder().build() } }
3. 测试优化
-
Mock依赖:替换生产环境Module,注入Mock对象。
@Module class TestRepositoryModule { @Provides fun provideRepository(): Repository = MockRepository() }
六、常见问题与解决方案
-
循环依赖
-
错误:
Error: [Component] Found cycle in dependency graph -
解决:重构代码,使用
Provider<T>延迟初始化。
-
-
作用域不匹配
-
错误:
@Singleton can only be used on an @Provides method if the @Provides method is in a @Module with a @Singleton -
解决:确保Module和Component的作用域注解一致。
-
-
性能优化
-
问题:生成代码过多导致编译慢。
-
方案:合理划分Component,避免过度设计。
-
七、总结
Dagger2通过编译时生成代码实现高效依赖注入,适用于中大型Android项目。其核心优势在于:
-
解耦:模块间依赖清晰,便于维护。
-
可测试性:依赖可替换,提升单元测试效率。
-
性能:无反射开销,生成代码接近手写效率。
参考
Dagger2依赖注入详解
1030

被折叠的 条评论
为什么被折叠?



