Koin Android ViewModel 完整指南生命周期感知注入、声明式 DSL 与作用域实战【免费下载链接】koinKoin - a pragmatic lightweight dependency injection framework for Kotlin Kotlin Multiplatform项目地址: https://gitcode.com/gh_mirrors/ko/koinKoin 为 Android 的ViewModel提供了一整套生命周期感知的注入能力既支持在Activity、Fragment、Service中通过by viewModel()懒加载获取实例也支持activityViewModel()共享、参数传递、SavedStateHandle自动注入、导航图作用域以及KoinViewModel注解/编译器插件声明等高级用法。本文基于 docs/reference/koin-android/viewmodel.md 展开并结合仓库源码koin-core-viewmodel、koin-android、koin-androidx-navigation、koin-android-compat逐层剖析底层实现帮助你在真实项目中安全、正确地使用 Koin 管理 ViewModel。概述Koin 如何支持 ViewModelViewModel 是 Android Architecture Components 中的核心组件用于在配置变更旋转、主题切换时保存 UI 相关数据。Koin 对 ViewModel 提供了专门支持其核心特性包括配置变更存活—— ViewModel 在旋转、主题切换等配置变更后依然保留生命周期作用域—— 绑定到 Activity、Fragment 或 Navigation Graph 的生命周期懒创建—— 仅在首次访问时才真正创建实例共享实例—— 可以在 Fragment 与宿主 Activity 之间共享同一个实例。从 Koin 源码看Android 侧的 ViewModel 支持建立在koin-core-viewmodel模块之上projects/core/koin-core-viewmodel该模块提供了跨平台的 ViewModel DSL 与解析内核koin-android再在其上提供面向ComponentActivity/Fragment的注入扩展。若需了解不依赖 Android 的多平台 ViewModel DSL参见 ViewModelkoin-coreCompose Multiplatform 场景参见 Compose ViewModel。作用域限制为什么 ViewModel 拿不到 Activity 作用域依赖需要特别强调的是ViewModel 是在 Koin 根作用域root scope下创建的无法访问 Activity 或 Fragment 作用域中的依赖。这样设计的目的在于防止内存泄漏——ViewModel 的存活时间通常长于其宿主 Activity / Fragment如果它持有了宿主作用域内的对象引用就会导致宿主无法被回收。如果你的 ViewModel 确实需要作用域依赖官方建议使用 ViewModel Scopekoin-core/scopes 创建一个与 ViewModel 生命周期绑定的独立作用域下文ViewModel 与作用域依赖一节有完整示例。声明 ViewModel三种 DSL 方式Koin 提供三种声明 ViewModel 定义的方式可按项目风格选用。方式一编译器插件 DSLCompiler Plugin DSLval appModule module { viewModelDetailViewModel() viewModelUserViewModel() }方式二注解Annotations配合 Koin 注解编译器用KoinViewModel标注类即可KoinViewModel class DetailViewModel( private val repository: DetailRepository ) : ViewModel() KoinViewModel class UserViewModel( private val userRepository: UserRepository ) : ViewModel()在 CoreAnnotations.kt 中可以看到KoinViewModel的定义它可标注类或函数所有构造函数依赖都会自动填充等价于生成viewModel { MyViewModel(get()) }并可通过binds参数声明额外的绑定类型。关于注解方式的更多细节可参考 Koin 注解参考。方式三经典 DSLClassic DSLval appModule module { // 构造引用方式 viewModelOf(::DetailViewModel) // Lambda 方式 viewModel { DetailViewModel(get()) } }实现原理无论哪种 DSLModule.viewModel本质上都注册为 Koin 的factory定义每次获取新建实例同时由 AndroidX 的ViewModelStore保证同一 store 内的复用。见 koin-core-viewmodel 的 ModuleExt.ktinline fun reified T : ViewModel Module.viewModel( qualifier: Qualifier? null, noinline definition: DefinitionT ): KoinDefinitionT { return factory(qualifier, definition) }注koin-android早期org.koin.androidx.viewmodel.dsl包下的同名扩展已标记Deprecated建议统一使用org.koin.core.module.dsl.*。注入 ViewModel懒加载与立即获取在Activity、Fragment或Service中注入 ViewModel 有两种方式by viewModel()—— 懒加载委托属性推荐getViewModel()—— 立即获取。class DetailActivity : AppCompatActivity() { // 懒加载注入 ViewModel private val viewModel: DetailViewModel by viewModel() // 或者立即获取 // private val viewModel: DetailViewModel getViewModel() }底层调用链ComponentActivity.viewModel()的实现位于 ActivityVM.kt其核心逻辑是MainThread inline fun reified T : ViewModel ComponentActivity.viewModel( qualifier: Qualifier? null, noinline extrasProducer: (() - CreationExtras)? null, noinline parameters: (() - ParametersHolder)? null, ): LazyT { return lazy(LazyThreadSafetyMode.NONE) { getViewModel(qualifier, extrasProducer, parameters) } }它返回LazyT委托首次访问时调用getViewModel()最终进入 GetViewModel.kt 的resolveViewModel()创建KoinViewModelFactory通过ViewModelProvider.create(viewModelStore, factory, extras)完成解析并依据qualifier/key计算 ViewModel keygetViewModelKey的规则是显式key优先有qualifier时使用qualifier.value_className否则用类名默认键。Fragment侧的viewModel()/getViewModel()实现逻辑相同只是额外支持通过ownerProducer指定ViewModelStoreOwner见 FragmentVM.kt。注意懒加载使用LazyThreadSafetyMode.NONE且标注MainThread应在主线程访问。共享 ViewModelFragment 与宿主 Activity 共用实例多个 Fragment 需要共享同一个 ViewModel 时使用activityViewModel()by activityViewModel()—— 懒加载委托getActivityViewModel()—— 立即获取。class WeatherActivity : AppCompatActivity() { private val weatherViewModel: WeatherViewModel by viewModel() } class WeatherHeaderFragment : Fragment() { // 与 Activity 共享 private val weatherViewModel: WeatherViewModel by activityViewModel() } class WeatherListFragment : Fragment() { // 与 WeatherHeaderFragment 拿到同一个实例 private val weatherViewModel: WeatherViewModel by activityViewModel() }实现原理activityViewModel()的默认ownerProducer是{ requireActivity() }即把宿主的 Activity 作为ViewModelStoreOwner从而与 Activity 使用同一个ViewModelStore见 FragmentActivityVM.kt。因此所有 Fragment 中解析到的是同一个实例并随 Activity 销毁而清理。为 ViewModel 传递参数编译器插件 DSLclass DetailViewModel( InjectedParam val itemId: String, private val repository: DetailRepository ) : ViewModel() val appModule module { viewModelDetailViewModel() }注解KoinViewModel class DetailViewModel( InjectedParam val itemId: String, private val repository: DetailRepository ) : ViewModel()经典 DSLval appModule module { viewModel { params - DetailViewModel( itemId params.get(), repository get() ) } }注入点传参在注入位置通过parametersOf(...)传入参数class DetailActivity : AppCompatActivity() { private val itemId: String by lazy { intent.getStringExtra(ITEM_ID)!! } // 注入时传入参数 private val viewModel: DetailViewModel by viewModel { parametersOf(itemId) } }参数最终会以ParametersHolder形式传入viewModel()的parameters参数见上文 ActivityVM.kt 的函数签名由 ViewModel 构造函数按位置或类型解析。SavedStateHandle自动注入只要把SavedStateHandle加进 ViewModel 构造函数Koin 就会自动注入无需任何额外声明注解方式KoinViewModel class MyStateViewModel( private val handle: SavedStateHandle, private val repository: MyRepository ) : ViewModel()DSL 方式class MyStateViewModel( private val handle: SavedStateHandle, private val repository: MyRepository ) : ViewModel() val appModule module { viewModelMyStateViewModel() // 编译器插件 DSL // 或 viewModelOf(::MyStateViewModel) // 经典 DSL }使用class DetailActivity : AppCompatActivity() { // SavedStateHandle 自动注入 private val viewModel: MyStateViewModel by viewModel() }实现原理Koin 在参数解析阶段AndroidParametersHolder.kt会检测构造函数参数类型是否为SavedStateHandle若是则通过CreationExtras.createSavedStateHandle()创建。当CreationExtras缺少SavedStateRegistryOwner时会抛出带有明确提示的异常提示将SavedStateHandle放在构造函数中而非懒加载/外部注入该行为有专门的测试用例 SavedStateHandleErrorTest.kt 覆盖。注意所有stateViewModel系列函数均已废弃请统一使用viewModel函数——SavedStateHandle会自动注入。导航图作用域 ViewModel可以把 ViewModel 的作用域绑定到 Navigation graph使同一导航图内的所有 Fragment 共享该实例class NavFragment : Fragment() { // 作用域绑定到导航图 private val navViewModel: NavViewModel by koinNavGraphViewModel(R.id.my_graph) }该 ViewModel 具备以下生命周期特征在图中第一个 Fragment 访问它时才创建同一导航图中的所有 Fragment 共享同一实例导航图被弹出pop时销毁。实现原理koinNavGraphViewModel定义在 NavGraphExt.kt属于koin-androidx-navigation模块。它通过findNavController().getBackStackEntry(navGraphId)拿到导航图的NavBackStackEntry作为ViewModelStoreOwner和默认CreationExtras再复用Fragment.viewModel()完成解析从而天然获得随图创建、随图销毁的生命周期。ViewModel 与作用域依赖如果 ViewModel 需要自己的作用域依赖而不是根作用域请使用 ViewModel Scope。声明方式val appModule module { viewModelScope { scopedUserCache() scopedUserRepository() viewModelUserViewModel() } }注解方式配合ViewModelScopeViewModelScope class UserCache ViewModelScope class UserRepository(private val cache: UserCache) KoinViewModel ViewModelScope class UserViewModel( private val repository: UserRepository ) : ViewModel()viewModelScope {}定义在 ViewModelScopeArchetypeDSL.kt它会创建一个以ViewModelScopeArchetype为 qualifier 的作用域段标记为KoinExperimentalAPI需启用viewModelScopeFactory()选项ViewModelScope注解定义见 CoreScopeArchetypes.kt。更完整的说明参见 Scopeskoin-core。ViewModel 通用 APIGeneric API对于进阶场景例如需要显式指定 key、owner 或 stateKoin 提供更低层的viewModelForClass// 从 ComponentActivity 或 Fragment 调用 val viewModel viewModelForClass( clazz MyViewModel::class, qualifier null, owner this, key null, parameters { parametersOf(param) } )其签名见 ViewModelLazy.kt支持clazz、qualifier、ownerViewModelStoreOwner、stateSavedStateDefinition、key与parameters六个维度返回LazyT。其中key与qualifier会直接影响ViewModelStore中的实例键参见上文getViewModelKey规则适合需要手动控制实例复用场景的开发者。Java 兼容koin-android-compat若项目以 Java 为主可添加兼容依赖implementation io.insert-koin:koin-android-compat:$koin_version然后通过ViewModelCompat的静态方法获取MyViewModel viewModel ViewModelCompat.getViewModel(this, MyViewModel.class);该 API 实现在 ViewModelCompat.kt内部通过resolveViewModelCompat使用owner.viewModelStore与全局根作用域解析实例同样支持qualifier、extrasProducer、parameters参数另提供viewModel()返回Lazy的懒加载版本。快速参考操作代码声明 ViewModelviewModelMyVM()/KoinViewModel在 Activity/Fragment 中注入by viewModel()与 Activity 共享by activityViewModel()传递参数by viewModel { parametersOf(id) }导航图作用域by koinNavGraphViewModel(R.id.graph)使用 SavedStateHandle直接加入构造函数即可相关文档与源码索引ViewModelkoin-core 多平台 DSLScopes含 ViewModel ScopeTestingViewModel 测试ComposeCompose 中的 ViewModel核心解析实现GetViewModel.kt、ModuleExt.ktkoin-core-viewmodel DSLAndroid 注入扩展ActivityVM.kt、FragmentVM.kt、FragmentActivityVM.kt导航图与 Java 兼容NavGraphExt.kt、ViewModelCompat.kt完整可运行示例可参考仓库中的 androidx-samples 与 sample-android-compose 示例模块。【免费下载链接】koinKoin - a pragmatic lightweight dependency injection framework for Kotlin Kotlin Multiplatform项目地址: https://gitcode.com/gh_mirrors/ko/koin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
珠海亨得利腕表服务一本通:从地址查询、电话预约到送修取表(2026年官方更新版) 亨得利全国统一服务电话:400-901-0695,广大表主可以通过该热线查询网点信息、预约腕表维保业务,也可以关注官方公众号“亨得利客户服务中心”,线上浏览全国重点区域门店资料。本次2026年官方更新版服务手册,重点面向珠… · 2026/9/24 15:49:48
EasyWeChat 4.x 小程序数据统计与分析(data_cube)实战指南 后端即时通讯 【免费下载链接】easywechat 📦 一个 PHP 微信 SDK 项目地址: https://gitcode.com/gh_mirrors/ea/easywechat 点击查看 免费下载 本指南围绕 EasyWeChat 4.x 中小程序的「数据统计与分析」(data_cube)模块展开&… · 2026/9/24 15:49:48
宠物保险理赔怎么证明是同一只宠物?鼻纹识别核验技术解析及选型参考 摘要:本文围绕宠物保险理赔中的身份核验难题,系统介绍了鼻纹识别技术的核心原理、与传统面部识别及芯片识别的对比、真实识别准确率与适用边界,并结合保险场景给出落地要点、常见问题解答和选型参考。文章指出,鼻纹识别凭借无创采… · 2026/9/24 15:49:48
Jetson agx xavier 虚拟机刷机 准备虚拟机
楼主虚拟机版本,测试过ubuntu18.04,20.04,(主板长按中间键,同时短按恢复键进入刷机模式,虚拟机检测到usb设备,选择虚拟机链接。)进入刷机模式后要保证USB端口能检测到,如… · 2026/9/24 17:38:00
手机连Mac热点看视频抢网速?终端命令限速搞定 Mac热点可让多台设备共享网络,但当某设备下载视频、更新系统时会抢占大量带宽,导致其他设备卡顿。macOS Sequoia没有直接提供图形化带宽限制界面,但通过终端、苹果开发工具或开源工具可实现精准管控。一、适配前提Mac需升级至macOS Sequoia&a… · 2026/9/24 17:38:00
React性能优化把我的列表渲染搞崩了 上周四凌晨两点,我在紧急回滚一个「优化」后的列表页——原本只是想给一个3000条数据的表格加上虚拟滚动,结果页面直接白屏,内存飙升到2GB。你一定也遇到过这种场景:明明是为了提升性能的改动,却让事情变得更糟。今天我… · 2026/9/24 17:37:54
基于大数据的保险行业客户数据分析与可视化系统-附源码 联系博主 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 … · 2026/9/24 17:37:47
流式数据平台兼容性处理(H5, 小程序,app) const getStreamMessage async (currentPicture, fileId) > {isPageLoading.value trueallChoose.value trueisFinish.value falseuni.showLoading({title: 加载中...,mask: true});// 👆 兼容处理结束isLoading.value true;// 请求获取数据const data {fi… · 2026/9/24 17:37:47
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44