ViewModel 在什么时候被销毁

在 Android 中,ViewModel 的销毁时机取决于它的作用域(即它关联的 ActivityFragment 的生命周期)。以下是具体的销毁规则:


1. ViewModel 被销毁的触发条件 • 当关联的 ActivityFragment 被永久销毁时(例如:用户按下返回键退出、调用 finish() 关闭 Activity,或系统因资源不足强制回收)。

• 当 Fragmentremovereplace 并从回退栈(Back Stack)中彻底移除时(如果 Fragment 未加入回退栈,则在 replace 时会立即销毁)。


2. ViewModel 不会被销毁的情况 • 配置变化(如屏幕旋转、语言切换):

ViewModel 的设计核心是 "在配置变化时存活"。当 Activity/Fragment 因配置变化重建时,ViewModel 会被保留,避免数据丢失。


3. ViewModel 的销毁流程

  1. 系统调用 onCleared() 方法:

    当 ViewModel 即将被销毁时,会自动触发 onCleared(),开发者可以在这里释放资源(如取消协程、关闭数据库连接等)。

    kotlin 复制代码
    class MyViewModel : ViewModel() {
        private val job = Job()
        override fun onCleared() {
            job.cancel() // 释放资源
            super.onCleared()
        }
    }
  2. 关联的 viewModelScope 自动取消:

    如果使用 viewModelScope 启动协程,当 ViewModel 销毁时,所有未完成的协程会自动取消(避免内存泄漏)。


4. 示例场景

场景 ViewModel 是否销毁?
旋转屏幕 ❌ 不销毁(配置变化)
从 Activity A 跳转到 B ❌ 不销毁(A 进入后台,未被销毁)
关闭 Activity(按返回键) ✅ 销毁(Activity 永久结束)
Fragment 被 replace 移除 ✅ 销毁(如果未加入回退栈)

ViewModel 的销毁与 Activity/Fragment 的 永久销毁 紧密绑定,而 不会因配置变化或临时进入后台 被销毁。这种设计保证了数据在屏幕旋转等场景下的稳定性,同时避免了内存泄漏。

在 Android Jetpack 的源码中,onCleared() 的调用时机与 Activity/Fragment 的生命周期销毁逻辑紧密相关。以下是其触发机制和源码实现的详细分析:


1. 触发时机 onCleared() 会在以下场景被调用: • 当 ActivityFragment 被永久销毁(非配置变化导致的重建,例如用户退出或调用 finish())。

• 当 Fragment 被彻底移除(未加入回退栈,或被 replace 后销毁)。


2. 源码实现流程 onCleared() 的调用逻辑通过 ViewModelStoreComponentActivity/Fragment 的生命周期监听实现,以下是核心源码链路:

(1) ViewModelStore 的清理逻辑 所有 ViewModel 实例存储在 ViewModelStore 中,当需要销毁时,会调用 ViewModelStore.clear()

java 复制代码
// 源码:ViewModelStore.java
public final class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear(); // 触发 onCleared()
        }
        mMap.clear();
    }
}

(2) Activity 中的触发链路ComponentActivity 监听生命周期:

ComponentActivity 在构造函数中注册了一个 LifecycleEventObserver,监听 ON_DESTROY 事件:

java 复制代码
// 源码:ComponentActivity.java
public ComponentActivity() {
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // 判断是否因配置变化导致销毁
                if (!isChangingConfigurations()) {
                    getViewModelStore().clear(); // 触发 ViewModelStore.clear()
                }
            }
        }
    });
}

• 关键条件:!isChangingConfigurations() 确保仅在永久销毁时清理 ViewModel。

(3) Fragment 中的触发链路FragmentManagerViewModel 管理销毁:

Fragment 的 ViewModel 清理由 FragmentManagerFragmentManagerViewModel 控制:

java 复制代码
// 源码:FragmentManagerViewModel.java
void clearNonConfigState(@NonNull Fragment f) {
    if (f.mViewModelStore != null) {
        f.mViewModelStore.clear(); // 触发 ViewModelStore.clear()
    }
}

• 当 Fragment 被永久移除时,FragmentManager 会调用此方法清理关联的 ViewModel。


3. 总结:源码调用链

scss 复制代码
Activity/Fragment 销毁(非配置变化)
    → LifecycleObserver 触发 ON_DESTROY 事件
        → 调用 ViewModelStore.clear()
            → 遍历所有 ViewModel 实例并调用 onCleared()
                → 开发者重写的 onCleared() 执行资源释放

4. 开发者如何利用 onCleared() 在自定义 ViewModel 中重写 onCleared(),释放资源或取消异步任务:

kotlin 复制代码
class MyViewModel : ViewModel() {
    private val job = Job()

    init {
        // 启动协程
        viewModelScope.launch(job) { /* ... */ }
    }

    override fun onCleared() {
        super.onCleared()
        job.cancel() // 手动取消协程(viewModelScope 会自动取消,此处仅为示例)
    }
}

关键点onCleared() 由系统自动调用,开发者无需手动触发。

• 配置变化不会触发 onCleared(),因为 ViewModel 会被保留。

• 源码通过 ViewModelStore 和生命周期监听 的协作,确保 ViewModel 在正确时机释放资源。

相关推荐
teacher伟大光荣且正确6 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
飞猿_SIR9 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen999 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇13 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
橙子1991101615 小时前
Kotlin 中的作用域函数
android·开发语言·kotlin
zimoyin15 小时前
Kotlin 懒初始化值
android·开发语言·kotlin
枣伊吕波16 小时前
第六节第二部分:抽象类的应用-模板方法设计模式
android·java·设计模式
萧然CS16 小时前
使用ADB命令操作Android的apk/aab包
android·adb
_extraordinary_20 小时前
MySQL 事务(二)
android·数据库·mysql
鸿蒙布道师1 天前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei