1. 为什么你需要 Kotlin 的 by viewModels()?
如果你开发 Android 应用超过半年,我敢打赌你肯定被屏幕旋转、应用切后台这类配置更改导致的数据丢失问题折磨过。辛辛苦苦加载的数据,用户一转手机,界面就空了,还得重新加载,体验差不说,用户可能直接就卸载了。以前我们怎么解决?用 onSaveInstanceState 保存 Bundle?太繁琐,而且数据量一大就不好使。用单例或者静态变量?内存泄漏的风险高得吓人。
这时候,Android 架构组件里的 ViewModel 就成了救星。它的设计初衷,就是为了在配置更改(比如旋转屏幕、切换系统语言)时,优雅地保存和管理 UI 相关的数据。ViewModel 的生命周期比 Activity 或 Fragment 更长,它不会因为屏幕旋转而被销毁重建,而是会一直存活到其关联的界面组件(Activity/Fragment)永久销毁(比如用户按返回键退出,或者系统回收资源)。
但是,ViewModel 好用,获取它的实例却一度有点麻烦。传统的写法是这样的:
class MyOldActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// 然后才能使用 viewModel
}
}
你得在 onCreate 里手动调用 ViewModelProvider(this).get(...)。这代码虽然不长,但有几个痛点:第一,它是样板代码,每个用到 ViewModel 的地方都得写一遍;第二,它不够类型安全,万一你手滑把 MyViewModel::class.java 写成了别的类,编译器可能不会立刻报错,但运行时就会崩溃;第三,它把初始化的逻辑和业务逻辑混在了一起。
而 by viewModels() 这个 Kotlin 属性委托,就是为了解决这些问题而生的。它让你能用一行极其简洁、声明式的代码,就安全地拿到 ViewModel 实例。就像下面这样:
class MyActivity : AppCompatActivity() {
private val myViewModel: MyViewModel by viewModels()
// 搞定!现在就可以在 onCreate 等任何地方直接使用 myViewModel 了
}
这行代码背后,Kotlin 的委托机制和 Android KTX 库帮你处理了所有复杂的初始化逻辑。它不仅让代码更干净,更重要的是,它把类型安全做到了极致。因为 myViewModel 的类型 MyViewModel 已经明确声明了,by viewModels() 会自动推导并返回正确类型的实例,你几乎不可能犯类名写错的低级错误。这就像是给你的代码上了一道保险,把很多潜在的运行时错误,提前到了编译期。
所以,by viewModels() 绝不仅仅是一个“语法糖”,它是将 Kotlin 的语言特性(委托)与 Android 官方架构组件(ViewModel)深度结合的最佳实践,是提升开发效率、增强代码健壮性的利器。接下来,我们就从最基础的用法开始,一步步把它吃透。
2. 5分钟上手:在 Activity 和 Fragment 中的基础用法
理论说再多,不如动手试一下。我们先来把环境搭好,然后看看在 Activity 和 Fragment 里怎么用这个“神器”。
2.1 环境准备:添加必要的依赖
要使用 by viewModels(),首先得确保你的项目引入了正确的库。它属于 Android KTX 扩展库的一部分。打开你的 app 模块下的 build.gradle.kts (如果你用 Kotlin DSL) 或者 build.gradle 文件,在 dependencies 块里添加以下依赖:
dependencies {
// ViewModel 核心库
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0")
// 如果你在 Activity 中使用
implementation("androidx.activity:activity-ktx:1.8.0")
// 如果你在 Fragment 中使用
implementation("androidx.fragment:fragment-ktx:1.6.2")
}
我这里的版本号写的是目前(撰写本文时)比较新的稳定版。你可以去 Android 开发者官网 查看最新版本。通常直接使用最新稳定版就好。添加完依赖,同步一下项目,准备工作就完成了。
注意:
lifecycle-viewmodel-ktx是必须的,它包含了 ViewModel 的核心功能和 KTX 扩展。而activity-ktx和fragment-ktx则分别提供了针对 Activity 和 Fragment 的by viewModels()扩展函数。如果你的模块里既有 Activity 也有 Fragment,把两个都加上也没问题。
2.2 在 Activity 中轻松获取 ViewModel
假设我们有一个简单的计数器应用,需要一个 ViewModel 来管理计数状态。我们先定义 ViewModel:
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
private val _count = MutableLiveData(0)
val count: LiveData<Int> get() = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
}
然后,在 Activity 中使用 by viewModels() 来获取它:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
// 核心代码:一行声明,自动获取 ViewModel 实例
private val viewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 直接使用 viewModel,无需手动初始化
viewModel.count.observe(this, Observer { newCount ->
countText.text = "Count: $newCount"
})
incrementButton.setOnClickListener {
viewModel.increment()
}
}
}
看到了吗?在 MainActivity 里,我们只是用 private val viewModel: CounterViewModel by viewModels() 声明了一个属性。在 onCreate 中,我们就可以直接使用 viewModel</


2899

被折叠的 条评论
为什么被折叠?



