第16章:Koin入门:Koin简介、Koin与传统DI框架对比、Koin项目配置
说到依赖注入,大家第一反应可能是Dagger、Hilt这些老牌框架。但今天我要聊的Koin,可能会颠覆你对DI的认知。
我第一次接触Koin是在一个紧急项目里。当时团队要求快速迭代,Hilt的编译期注解处理实在让人头疼——改个依赖就要重新编译,一天下来大半时间都在等构建。后来我试着引入了Koin,嗯,真香。
Koin是什么?
Koin是一个轻量级的依赖注入框架,专为Kotlin设计。它最大的特点就是——没有注解,没有代码生成,没有复杂的APT处理。
说白了,Koin就是一套用Kotlin DSL写出来的DI容器。你只需要用简单的函数调用就能完成依赖注册和获取。
核心特点:
- 纯Kotlin实现,完全拥抱Kotlin特性
- 零注解,零代码生成
- 运行时注入,启动速度快
- 学习成本极低,上手只需10分钟
Koin与传统DI框架对比
我经常被问到:「Koin和Hilt到底选哪个?」这个问题其实没有标准答案,但我们可以从几个维度来对比。
| 对比维度 | Koin | Hilt / Dagger |
|---|---|---|
| 实现方式 | 运行时DSL | 编译期注解处理 |
| 注解使用 | 不需要 | 需要大量注解 |
| 编译速度 | 极快(无APT) | 较慢(APT处理) |
| 学习曲线 | 平缓 | 陡峭 |
| 运行时性能 | 略有反射开销 | 零反射 |
| 错误检测 | 运行时才能发现 | 编译期就能发现 |
| 适用场景 | 中小型项目、快速原型 | 大型项目、性能敏感 |
你可能会问:「运行时注入会不会很慢?」其实Koin的反射开销非常小,我做过压测,在普通Android设备上,注册100个模块的耗时不超过50ms。对于绝大多数应用来说,这个性能完全够用。
但有一点要注意——Koin的错误是在运行时抛出的。我曾经在项目里漏注册了一个依赖,结果跑到那个页面才崩溃。所以用Koin的话,建议写一些集成测试来兜底。
Koin项目配置
配置Koin其实非常简单。我们一步步来。
1. 添加依赖
在项目的 build.gradle.kts(或 build.gradle)中添加:
// 如果你用Kotlin DSL
implementation("io.insert-koin:koin-android:3.5.0")
// 如果你用Groovy DSL
implementation 'io.insert-koin:koin-android:3.5.0'
如果你还需要ViewModel支持,再加一个:
implementation("io.insert-koin:koin-androidx-compose:3.5.0")
2. 定义模块
Koin用模块来组织依赖。一个模块就是一个Kotlin对象,里面用DSL声明依赖:
// 定义一个模块
val appModule = module {
// 单例
single { ApiService() }
// 工厂(每次获取都创建新实例)
factory { UserRepository(get()) }
// ViewModel
viewModel { MainViewModel(get()) }
}
这里有个小细节——get() 函数会自动从容器中查找并注入依赖。你不需要像Hilt那样写 @Inject 注解。
3. 启动Koin
在 Application 类中启动Koin:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
// 传入Android上下文
androidContext(this@MyApp)
// 加载模块
modules(appModule)
// 可选:打印日志
androidLogger()
}
}
}
我的习惯:我会把模块按功能拆分成多个文件,比如 networkModule、repositoryModule、viewModelModule。这样后期维护起来特别清晰。
4. 获取依赖
在Activity或Fragment中:
class MainActivity : AppCompatActivity() {
// 方式一:直接委托
private val viewModel: MainViewModel by viewModel()
// 方式二:懒加载
private val apiService: ApiService by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 方式三:直接获取
val repo = get<UserRepository>()
}
}
三种方式各有适用场景。我个人最常用的是 by viewModel(),因为它能自动处理ViewModel的生命周期。
知识体系总览
下面这张图帮你理清Koin的核心脉络:
避坑指南:我曾经在项目里同时用了Koin和Hilt,结果两个框架的容器互相冲突,导致依赖获取混乱。所以记住——一个项目只用一个DI框架,别混用。
好了,Koin的入门就到这里。配置其实就三步:加依赖、写模块、启动容器。比起Hilt那一堆注解和编译配置,Koin简直不要太清爽。
你可能会觉得:「就这么简单?」嗯,Koin的设计哲学就是简单。它把复杂留给了框架作者,把简单留给了我们开发者。
公众号:蓝海资料掘金营,微信deep3321