在kotlin的安卓项目中使用dagger
在 Kotlin 的 Android 项目中使用 Dagger(特别是 Dagger Hilt,官方推荐的简化版)进行依赖注入(DI)可以大幅提升代码的可测试性和模块化程度。
1. 配置 Dagger Hilt
1.1 添加依赖
在 build.gradle
(Module) 中:
plugins {id("com.google.dagger.hilt.android") version "2.48" apply false
}dependencies {implementation("com.google.dagger:hilt-android:2.48")kapt("com.google.dagger:hilt-compiler:2.48") // Kotlin 注解处理器
}
在 build.gradle
(Project) 中:
plugins {id("com.google.dagger.hilt.android") version "2.48" apply false
}
1.2 启用 Hilt
在 Application
类上添加 @HiltAndroidApp
:
@HiltAndroidApp
class MyApp : Application()
2. 核心注解与用法
2.1 注入依赖到 Android 类
使用 @Inject
标记需要注入的依赖,并在目标类(如 Activity
、Fragment
)上添加 @AndroidEntryPoint
:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Inject lateinit var myDependency: MyDependency // 依赖注入override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)myDependency.doSomething() // 直接使用}
}
2.2 提供依赖(Module)
使用 @Module
和 @Provides
定义依赖:
@Module
@InstallIn(SingletonComponent::class) // 作用域为全局单例
object AppModule {@Providesfun provideMyDependency(): MyDependency = MyDependencyImpl()
}
2.3 作用域(Scoping)
@Singleton
:全局单例(整个应用生命周期)。@ActivityScoped
:与 Activity 生命周期绑定。@ViewModelScoped
:与 ViewModel 生命周期绑定。
@Module
@InstallIn(ViewModelComponent::class) // 作用域为 ViewModel
object ViewModelModule {@ViewModelScoped@Providesfun provideMyViewModelDependency(): MyViewModelDependency = MyViewModelDependencyImpl()
}
3. 注入 ViewModel
结合 ViewModel
和 Hilt
:
@HiltViewModel
class MyViewModel @Inject constructor(private val myDependency: MyDependency
) : ViewModel() {fun doWork() {myDependency.doSomething()}
}
在 Activity/Fragment
中获取:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MyViewModel by viewModels()
}
4. 注入接口或第三方库
4.1 接口绑定(@Binds)
interface MyRepository {fun getData(): String
}class MyRepositoryImpl @Inject constructor() : MyRepository {override fun getData() = "Data from Repository"
}@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {@Bindsabstract fun bindMyRepository(impl: MyRepositoryImpl): MyRepository
}
4.2 注入 Retrofit / Room
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {@Providesfun provideRetrofit(): Retrofit {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build()}@Providesfun provideApiService(retrofit: Retrofit): ApiService {return retrofit.create(ApiService::class.java)}
}
5. 常见问题与解决
5.1 编译错误:Cannot be provided without an @Provides
- 原因:Dagger 找不到依赖的提供方式。
- 解决:
- 检查是否正确定义了
@Module
和@Provides
。 - 确保
@Inject
的类可以被 Dagger 构造(如非接口、非第三方库类)。
- 检查是否正确定义了
5.2 作用域冲突
- 错误示例:在
Activity
中注入@Singleton
依赖,但该依赖需要@ActivityScoped
。 - 解决:调整
@InstallIn
和作用域注解,确保生命周期匹配。
5.3 延迟注入(Lazy)
如果依赖初始化耗时,可以使用 Lazy<T>
:
@Inject lateinit var heavyDependency: Lazy<HeavyDependency>fun useDependency() {heavyDependency.get().doWork() // 使用时才初始化
}
6. Dagger Hilt vs. Dagger 2
特性 | Dagger Hilt | Dagger 2 |
---|---|---|
配置复杂度 | 低(自动生成组件) | 高(需手动定义组件) |
作用域管理 | 内置 Android 生命周期作用域(如 @ActivityScoped ) | 需自定义作用域 |
适用场景 | 标准 Android 项目 | 需要高度定制的复杂项目 |
7. 最佳实践
- 避免全局过度使用
@Singleton
,按需选择作用域。 - 用
@Binds
替代@Provides
注入接口,减少模板代码。 - 结合 ViewModel 使用,避免内存泄漏。
class DeviceManager @Inject constructor(private val aService: IAService,private val bService: IBService
) {
@Inject 注解的作用 这里的 @Inject constructor() 表示该构造函数由依赖注入框架(如 Dagger/Hilt)管理,框架会自动创建 DeviceCmdManager 实例,并注入其依赖项 bleService 和 mqttService。
依赖注入框架会根据类型(IAService/IBService)自动寻找对应的实现类,开发者无需手动实例化这些服务对象。
使用场景示例 当其他类需要 DeviceManager 时,只需声明依赖即可自动获取实例class SomeViewModel @Inject constructor(private val manager: DeviceManager // 自动注入)