You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中@Inject与by viewModels()获取ViewModel的核心差异及理解验证

关于ViewModel两种获取方式的理解纠正与说明

你的理解有部分正确,但存在关键误区,下面逐一拆解:

一、by viewModels()的理解完全正确

by viewModels()是Jetpack官方提供的Kotlin扩展,核心逻辑是依托宿主(Activity/Fragment)的ViewModelStore来缓存实例:

  • 只要宿主没被彻底销毁(比如仅发生屏幕旋转这类配置变更),每次调用都会返回同一个ViewModel实例;
  • 它天然遵循ViewModel的生命周期规则,配置变更时实例会被保留,直到宿主真正退出才会被清理。

你的代码示例是标准用法:

val viewModel: BookMarkImageViewModel by viewModels()

二、@Inject获取ViewModel的理解有偏差

你提到“未加@Singleton时@Inject每次都会创建新实例”,这个说法不准确,核心问题在于ViewModel的实例管理要同时兼顾Dagger作用域和ViewModel的生命周期规范:

1. 直接@Inject是错误用法

你写的这种直接注入方式:

@Inject
lateinit var viewModel: BookMarkImageViewModel

本质上是把ViewModel当成了普通依赖,它不受ViewModelStore管理,完全失去了ViewModel的生命周期特性:

  • 如果Dagger中给这个ViewModel没配置任何作用域,每次注入确实会生成新实例;
  • 就算加了@Singleton,虽然能拿到全局单例,但会导致ViewModel脱离宿主生命周期,引发内存泄漏或多页面状态混乱(比如多个Activity共享同一个ViewModel)。

2. 正确的Dagger注入ViewModel姿势

正确的做法是通过ViewModelProvider.Factory结合Dagger注入,让ViewModel同时受Dagger作用域和ViewModelStore管控:

  • 给ViewModel绑定与宿主生命周期匹配的作用域(比如Jetpack提供的@ActivityRetainedScope,这个作用域会跨配置变更保留实例),此时@Inject会在宿主生命周期内返回同一个实例,效果和by viewModels()完全一致;
  • 根本不需要用@Singleton,因为ViewModel的生命周期应该和宿主绑定,而非全局单例。

总结

  • by viewModels()是ViewModel的标准用法,你的理解没问题;
  • @Inject的行为取决于配置:直接注入是错误用法,正确结合ViewModelFactory和匹配作用域后,也能实现生命周期绑定的实例复用,并非必须加@Singleton才会复用。

内容的提问来源于stack exchange,提问作者user9628944

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:47:35