Koin 依赖注入深度解析:Single、Factory 与 Scoped 到底怎么选?

在 Kotlin 的世界里,Koin 以其"无反射、极简 DSL"的特性让开发者倍感幸福。但要用好 Koin,理解其三大核心定义类型:singlefactoryscoped 是必修课。


一、 single:全局唯一的单例 (Singleton)

single 是 Koin 中最常用的定义方式。

  • 本质 :在整个 Koin 容器的生命周期内(通常是应用的生命周期),该定义的实例只会被创建一次。后续所有的注入请求都会返回同一个对象。

  • 生命周期:与应用进程共存亡。

  • 适用场景

    • Repository 层:数据仓库通常不需要重复创建。
    • 网络模块:如 Retrofit 实例、OkHttpClient。
    • 本地数据库:如 Room 数据库实例。

代码示例:

Kotlin

java 复制代码
val appModule = module {
    // 整个应用运行期间,只有一个 UserRepository 实例
    single { UserRepository(get()) }
}

二、 factory:按需创建的工厂 (Factory)

single 相反,factory 每次都会给你提供一个"全新的"对象。

  • 本质 :每次进行注入(通过 inject()get())时,Koin 都会执行一次代码块,创建一个新的实例

  • 生命周期:Koin 不负责保存这个实例,它的生命周期由调用者决定(例如被赋值给某个局部变量)。

  • 适用场景

    • 临时的 UI 逻辑类:不需要持久化状态的小工具。
    • 具有状态的对象:你不希望不同页面共享同一个状态的对象。

代码示例:

Kotlin

java 复制代码
val appModule = module {
    // 每次注入都会创建一个新的 Presenter 实例
    factory { UserPresenter(get()) }
}

三、 scoped:受控的作用域 (Scoped)

这是 Koin 中最强大但也最容易被误解的部分。它介于 singlefactory 之间。

  • 本质:实例在一个特定的**作用域(Scope)**内是唯一的。当作用域开启时创建,当作用域关闭(如 Activity 销毁)时,该实例也会随之销毁。

  • 生命周期:绑定到特定的组件生命周期。

  • 适用场景

    • 分步表单/向导界面:在 3 个 Fragment 之间共享数据,但一旦退出该流程,数据应立即清除。
    • Activity 专有数据:只在某个特定页面及其内部子组件中共享。

代码示例:

Kotlin

java 复制代码
val appModule = module {
    // 定义一个作用域
    scope<MyActivity> {
        // 在 MyActivity 的生命周期内,该实例是单例
        scoped { UserSession() }
    }
}

四、 核心差异对比表

特性 single factory scoped
实例数量 全局只有一个 每次请求都有一个新实例 作用域内唯一
内存占用 持续占用,直到应用关闭 瞬时占用,随用随关 随作用域生命周期释放
实例共享 全局共享 不共享 仅在当前作用域内共享
推荐用途 数据库、API 客户端、Repo 工具类、瞬时数据处理 页面私有逻辑、分步任务流

五、 避坑与最佳实践

  1. 关于 ViewModel :在 Android 中,Koin 提供了专用的 viewModel { ... } 关键字。它的行为类似于 factory,但由系统的 ViewModelProvider 托管,确保在配置更改(如旋转屏幕)时实例不被销毁。
  2. 避免滥用 single :虽然 single 很省事,但如果把太多具有状态的逻辑类定义为单例,会导致内存积压,甚至出现"退出登录后数据未清理"的诡异 Bug。
  3. Scoped 的自动释放 :在 Android 中使用 scoped 时,建议配合 ActivityScopeFragmentScope 的扩展,这样 Koin 能在组件 onDestroy() 时自动帮你回收资源,避免内存泄漏。
相关推荐
折翅鵬2 小时前
Android史诗级网络优化实践总结
android·网络
赏金术士4 小时前
Android 项目模块化与 Feature 组件实践
android·kotlin·模块化
_qingche8 小时前
H2 数据库到 MySQL 数据迁移
java·数据库·spring boot·mysql·spring·重构·kotlin
summerkissyou19878 小时前
Android-UI-获取屏幕尺寸的方法
android·ui
用户86022504674728 小时前
Kotlin 函数式编程入门与实践指南
android
最爱睡觉睡觉睡觉9 小时前
CSS → Flutter 对照手册
android·前端
xingpanvip10 小时前
星盘接口开发文档:马盘次限盘接口指南
android·开发语言·python·php·lua
用户261904985615711 小时前
JUnit4 完整配置流程
android
用户261904985615711 小时前
JaCoCo 完整配置流程
android
QING61811 小时前
Android面试 —— 八股文之app启动流程
android·面试·app