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() 时自动帮你回收资源,避免内存泄漏。
相关推荐
hunterandroid4 小时前
[鸿蒙从零到一] ArkUI 声明式渲染管线深度解析:Diff、复用与局部刷新
android
JMchen1235 小时前
Jetpack 内核实战(十):实战(下)——编辑页、全局设置与内存泄漏排查
kotlin·内存泄漏·android 实战·datastore 设置·jetpack 项目优化·编辑页开发
林栩link5 小时前
【车载 Android】从 AAR 到 Plugin:Launcher 卡片插件化解耦实践
android
小小测试开发6 小时前
RAG应用评测:从指标体系到LLM-as-a-Judge的自动化落地
android·运维·人工智能·自动化
paopao_djshddhdj6 小时前
钉钉与钉钉服务商有什么区别?为什么建议选择服务商
android·钉钉
xcLeigh6 小时前
Go入门:rune与byte的区别和使用场景
android·javascript·golang
恋猫de小郭7 小时前
Firebase 如何让全球 Android 和 Flutter 开发者集体 Build Fail
android·前端·flutter
我命由我123457 小时前
Android Camera - 获取当前设备屏幕的旋转角度、保存帧到外部存储的私有空间
android·java·开发语言·java-ee·android jetpack·android-studio·android runtime
DogDaoDao7 小时前
HarmonyOS 深度解析:从微内核到 ArkTS 工程实战
android·linux·ios·华为·程序员·harmonyos·harmonyos next
小成很成16 小时前
mysql 8.0.21 升级 mysql 8.0.45(经过生产环境验证)
android·mysql·adb