
依赖注入(Dependency Injection, DI)是一种设计模式,其核心思想是:将对象所需的依赖由外部提供,而不是在对象内部自行创建。这样可以实现控制反转(Inversion of Control, IoC),提升代码的可测试性、可维护性和解耦程度。
class Car {
private val engine = Engine() // 直接创建依赖,耦合度高
fun start() {
engine.start()
}
}Car 类与 Engine 紧耦合,难以替换或测试。class Car(private val engine: Engine) { // 依赖通过构造函数注入
fun start() {
engine.start()
}
}Car 不关心 Engine 如何创建。// 1. 使用 @Inject 标记可注入的类
class Engine @Inject constructor() {
fun start() {
println("Engine started")
}
}
class Car @Inject constructor(
private val engine: Engine
) {
fun drive() {
engine.start()
println("Car is driving")
}
}
// 2. 定义 Component 接口,作为依赖图的入口
@Component
interface CarComponent {
fun getCar(): Car
fun inject(mainActivity: MainActivity)
}
// 3. 使用
class MainActivity : AppCompatActivity() {
@Inject lateinit var car: Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 手动触发注入
DaggerCarComponent.create().inject(this)
car.drive()
}
}Dagger 是编译时依赖注入框架,通过注解处理器生成代码,性能高但配置复杂。
Hilt 简化了 Dagger 在 Android 中的使用,提供标准组件和作用域。
// build.gradle (app)
plugins {
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
dependencies {
implementation "com.google.dagger:hilt-android:2.48"
kapt "com.google.dagger:hilt-compiler:2.48"
}@HiltAndroidApp
class MyApplication : Application()// 定义 Module 提供依赖
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"app.db"
).build()
}
@Provides
fun provideUserRepository(
database: AppDatabase
): UserRepository = UserRepositoryImpl(database)
}
// Activity 中使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var userRepository: UserRepository
@Inject lateinit var analytics: AnalyticsService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 依赖已自动注入
userRepository.getUsers()
}
}
// Fragment 中使用
@AndroidEntryPoint
class UserFragment : Fragment() {
@Inject lateinit var viewModelFactory: UserViewModelFactory
private val viewModel: UserViewModel by viewModels { viewModelFactory }
}@HiltViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val users = userRepository.getUsers().asLiveData()
fun addUser(user: User) {
viewModelScope.launch {
userRepository.insertUser(user)
}
}
}
// 在 Activity/Fragment 中直接使用
@AndroidEntryPoint
class UserActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
}
@HiltViewModel+by viewModels()实现零配置 ViewModel 注入。
Koin 是一个基于 Kotlin DSL 的轻量级依赖注入框架,使用运行时反射,简单易上手。
dependencies {
implementation "io.insert-koin:koin-android:3.5.0"
}val appModule = module {
single { AppDatabase.getInstance(androidContext()) }
single<UserRepository> { UserRepositoryImpl(get()) }
factory { (userId: String) -> UserDetailViewModel(userId, get()) }
}class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApplication)
modules(appModule)
}
}
}class MainActivity : AppCompatActivity() {
private val userRepository: UserRepository by inject()
private val viewModel: UserViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userRepository.getUsers()
}
}Koin 适合中小型项目,学习成本低,无需注解处理器。
方式 | 控制权 | 特点 |
|---|---|---|
传统方式 | 类内部 | new UserRepository(),紧耦合 |
DI 方式 | 外部容器 | 依赖由外部注入,松耦合 |
// 没有 DI
class UserService {
private val repository = UserRepository() // 自己控制创建
}
// 使用 DI
class UserService(private val repository: UserRepository) // 外部提供class UserService(private val repository: UserRepository)class UserService {
lateinit var repository: UserRepository
}interface RepositoryInjector {
fun injectRepository(repository: UserRepository)
}
class UserService : RepositoryInjector {
private lateinit var repository: UserRepository
override fun injectRepository(repository: UserRepository) {
this.repository = repository
}
}完整 Hilt 配置
// 数据源接口
interface NetworkDataSource {
suspend fun fetchUsers(): List<User>
}
@Singleton
class NetworkDataSourceImpl @Inject constructor(
private val apiService: ApiService
) : NetworkDataSource {
override suspend fun fetchUsers(): List<User> {
return apiService.getUsers()
}
}
// 仓库接口
interface UserRepository {
suspend fun getUsers(): List<User>
}
@Singleton
class UserRepositoryImpl @Inject constructor(
private val networkDataSource: NetworkDataSource,
private val localDataSource: LocalDataSource
) : UserRepository {
override suspend fun getUsers(): List<User> {
return networkDataSource.fetchUsers()
}
}
// ViewModel
@HiltViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users = _users.asStateFlow()
fun loadUsers() {
viewModelScope.launch {
_users.value = userRepository.getUsers()
}
}
}
// Module:网络层
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
// Module:数据层
@Module
@InstallIn(SingletonComponent::class)
object DataModule {
@Provides
@Singleton
fun provideNetworkDataSource(apiService: ApiService): NetworkDataSource {
return NetworkDataSourceImpl(apiService)
}
@Provides
@Singleton
fun provideUserRepository(
networkDataSource: NetworkDataSource,
localDataSource: LocalDataSource
): UserRepository {
return UserRepositoryImpl(networkDataSource, localDataSource)
}
}@Singleton // 整个应用生命周期
@ActivityScoped // Activity 生命周期
@FragmentScoped // Fragment 生命周期
@ViewModelScoped // ViewModel 生命周期Hilt 提供了标准作用域,避免内存泄漏。
class UserViewModel @Inject constructor(
private val userRepository: UserRepository // 接口
) : ViewModel()TestUserRepository)class TestUserRepository : UserRepository {
override suspend fun getUsers(): List<User> = listOf(User("Test"))
}val networkModule = module { /* 网络相关依赖 */ }
val databaseModule = module { /* 数据库相关依赖 */ }
val repositoryModule = module { /* 仓库相关依赖 */ }
// Koin 启动时加载
startKoin {
modules(networkModule, databaseModule, repositoryModule)
}按功能划分模块,便于维护和复用。
优势 | 说明 |
|---|---|
可测试性 | 可轻松注入 Mock 对象进行单元/集成测试 |
代码复用 | 依赖可在多个组件间共享(如数据库实例) |
解耦 | 类不再负责创建依赖,职责单一 |
可维护性 | 依赖关系集中管理,易于修改和追踪 |
生命周期管理 | 框架自动管理对象生命周期(如单例) |
依赖注入是现代 Android 开发中不可或缺的设计模式,尤其在结合 Hilt 或 Koin 等框架后,能够显著提升开发效率和代码质量。
项目规模 | 推荐框架 | 理由 |
|---|---|---|
中大型项目 | Hilt | Google 官方推荐,编译时安全,与 Android 组件深度集成 |
小型项目 / 快速原型 | Koin | 轻量、无注解处理器、Kotlin DSL 友好 |
通过合理的依赖注入设计,可以构建出高内聚、低耦合、易测试、易维护的 Android 应用架构。
建议:新项目优先使用 Hilt,它是 Android 生态中 DI 的未来标准。