第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()
        }
    }
}

我的习惯:我会把模块按功能拆分成多个文件,比如 networkModulerepositoryModuleviewModelModule。这样后期维护起来特别清晰。

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 知识体系总览 Koin DI 框架 核心概念 • module { } 定义模块 • single { } 单例模式 • factory { } 工厂模式 配置方式 • startKoin { } 启动 • androidContext() 上下文 • modules() 加载模块 获取方式 • by inject() 懒加载 • by viewModel() ViewModel • get<T>() 直接获取 特点:零注解 · 零生成 · 纯Kotlin · 轻量级

避坑指南:我曾经在项目里同时用了Koin和Hilt,结果两个框架的容器互相冲突,导致依赖获取混乱。所以记住——一个项目只用一个DI框架,别混用。

好了,Koin的入门就到这里。配置其实就三步:加依赖、写模块、启动容器。比起Hilt那一堆注解和编译配置,Koin简直不要太清爽。

你可能会觉得:「就这么简单?」嗯,Koin的设计哲学就是简单。它把复杂留给了框架作者,把简单留给了我们开发者。


公众号:蓝海资料掘金营,微信deep3321