一、Lifecycle
什么是 Lifecycle?
Lifecycle 是Jetpack 架构组件中的核心类,用于统一管理 Android 组件(Activity、Fragment 等)的生命周期,并通过观察者模式向外部暴露生命周期的变化。
传统上,我们需要在 onCreate、onStart、onDestroy 等方法里手动写逻辑,很容易产生内存泄漏或重复代码。而 Lifecycle 的引入,让我们可以只关心“生命周期状态的变化”,而不用和具体回调方法绑定。
Lifecycle 本质上就是一个抽象类,提供了注册和移除观察者的能力:
public abstract class Lifecycle {
// 添加观察者
public abstract fun addObserver(observer: LifecycleObserver)
// 删除观察者
public abstract fun removeObserver(observer: LifecycleObserver)
}而 Activity、Fragment 等组件则实现了 LifecycleOwner 接口,要求提供一个 lifecycle 属性:
public interface LifecycleOwner {
/**
* 返回该组件的 Lifecycle
*/
public val lifecycle: Lifecycle
}这样一来,我们就能在任意地方对生命周期进行观察,而不必耦合到 Activity/Fragment 的具体方法中。
lifecycleScope
有了生命周期的监听机制,Google 官方进一步提供了协程作用域:lifecycleScope。它是 LifecycleOwner 的扩展属性,可以直接在 Activity 或 Fragment 中使用:
lifecycleScope.launch {
// 在生命周期结束时自动取消
}为什么会自动取消?因为在 LifecycleOwner.kt 中,Google 用 原子引用 + CAS 的方式,确保每个生命周期只持有一个唯一的 LifecycleCoroutineScope:
// LifecycleOwner.kt
public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
get() = lifecycle.coroutineScope
// Lifecycle.kt
public val Lifecycle.coroutineScope: LifecycleCoroutineScope
get() {
while (true) {
val existing = internalScopeRef.get() as LifecycleCoroutineScopeImpl?
if (existing != null) {
return existing
}
val newScope = LifecycleCoroutineScopeImpl(
this,
SupervisorJob() + Dispatchers.Main.immediate
)
if (internalScopeRef.compareAndSet(null, newScope)) {
newScope.register() // 将协程作用域注册到 Lifecycle
return newScope
}
}
}LifecycleCoroutineScopeImpl 是 lifecycleScope 的实际实现。它本身就是一个 LifecycleEventObserver,会随着生命周期的变化自动管理协程:
internal class LifecycleCoroutineScopeImpl(
override val lifecycle: Lifecycle,
override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
init {
// 初始化时如果 Lifecycle 已经销毁,则立即取消协程
if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
coroutineContext.cancel()
}
}
fun register() {
launch(Dispatchers.Main.immediate) {
if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
} else {
coroutineContext.cancel()
}
}
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
lifecycle.removeObserver(this) // 移除观察者
coroutineContext.cancel() // 取消协程
}
}
}
总结:lifecycleScope 作用域会注册为观察者,当状态变为 DESTROYED 时自动取消协程,避免内存泄漏,开发者不再需要手动 cancel() 协程。
二、ViewModel
什么是 ViewModel
ViewModel 属于Android Jetpack 库的一部分,是一种业务逻辑或屏幕状态容器。它主要具有以下两种优势:
数据持久保存:ViewModel 的生命周期通常比 Activity/Fragment 更长。在界面因为屏幕旋转等原因被销毁并重建时,ViewModel 不会随之销毁,因此非常适合保存 UI 状态数据,无需在页面重建时手动恢复。
避免内存泄漏:ViewModel 基于
Lifecycle机制管理,当宿主(Activity/Fragment)销毁后,ViewModel 会自动清理,避免了常见的内存泄漏问题。
ViewModel 的使用
使用 ViewModel 的方式很简单:只需继承 ViewModel 类即可。
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
var count = 0 // ViewModel 变量(Activity 重建后不会丢失)
fun increment() {
count++
}
}在 Activity/Fragment 中并不是直接 new,而是通过 ViewModelProvider 获取实例:
class MainActivity : AppCompatActivity() {
// 获取 ViewModel 实例
private val viewModel: CounterViewModel by lazy {
ViewModelProvider(this)[CounterViewModel::class.java]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.tv_count)
val button: Button = findViewById(R.id.btn_increment)
// 显示当前计数
textView.text = viewModel.count.toString()
// 按钮自增
button.setOnClickListener {
viewModel.increment()
textView.text = viewModel.count.toString()
}
}
}即使旋转屏幕,count 的值依旧会被保留,不会被重置。
通过 KTX 获取 ViewModel
Android KTX 扩展库提供了更简洁的用法,在 build.gradle 中引入:
implementation("androidx.activity:activity-ktx:1.11.0")然后可以直接使用 by viewModels() 获取 ViewModel 实例,这样写更简洁,也更符合 Kotlin 的风格。
private val viewModel: CounterViewModel by viewModels()ViewModel 的生命周期
ViewModel 的生命周期取决于它所在的作用域(ViewModelStoreOwner),通常是 Activity 或 Fragment。
它会一直存活,直到作用域销毁时才会回收。
在回收前,会触发 onCleared() 方法,适合做一些资源释放的操作。

viewModelScope
viewModelScope 是 ViewModel 提供的一个扩展属性,代表一个与 ViewModel 生命周期绑定的协程作用域。
它的好处是:当 ViewModel 被销毁时,协程会自动取消,避免协程泄漏。借助 viewModelScope,我们可以在 ViewModel 中安全地执行异步任务(如网络请求、数据库操作),同时保证资源得到正确回收。
viewModelScope.launch {
// ViewModel onCleared 时自动取消协程
}三、LiveData
LiveData 搭配 ViewModel 是 MVVM 模式的最佳实践。
Flow
ViewBinding
DataBinding
什么是 DataBinding?
DataBinding 是谷歌官方发布的一个实现数据绑定的框架(实现数据与视图的双向绑定),DataBinding 可以帮助我们在 Android 中更好的实现 MVVM 模式。
DataBinding 的使用步骤
1. 启用 DataBinding
在 build.gradle.kts 中,配置启用 DataBinding:
android {
// ...
dataBinding {
enable = true
}
}2. 修改布局文件为 DataBinding 布局
在 Android Studio 中,打开布局文件,选中最外层的布局标签,按下 ALT + 回车 键,选择 Convert to data binding layout,就可以自动转化为 DataBinding 布局。

3. 数据绑定
转换为 DataBinding 布局后,可以在布局文件中的 <data> 标签内定义变量 <variable>,设置好变量名和类型。然后就可以在布局中通过 "@{}" 的形式直接使用变量。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="account"
type="top.tonydon.interview.mvvm.bean.Account" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".databinding.DemoActivity">
<TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{account.name + '|' + account.level}" />
<Button
android:layout_marginTop="50dp"
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账号等级 +1" />
</LinearLayout>
</layout>在 Activity 中需要使用 DataBindingUtil 进行 setContentView(),它返回一个 ActivityDemoBinding 示例,通过它可以直接拿到布局中的 View、对变量赋值会自动更新 UI。
class DemoActivity : AppCompatActivity() {
val account = Account("Tony", 100)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 通过 DataBindingUtil 设置 ContentView,返回一个 ActivityDemoBinding 实例(系统自动生成)
val binding: ActivityDemoBinding =
DataBindingUtil.setContentView(this, R.layout.activity_demo)
// 直接为 account 属性赋值
binding.account = account
// 告别繁琐的 findViewById,可以直接根据 id 获取 View 实例
binding.btnAdd.setOnClickListener {
account.level += 1
binding.account = account // 赋值 account,UI 会自动更新
}
}
}