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 在正确时机释放资源。

相关推荐
tmacfrank36 分钟前
Android 网络全栈攻略(四)—— TCPIP 协议族与 HTTPS 协议
android·网络·https
fundroid2 小时前
Kotlin 协程:Channel 与 Flow 深度对比及 Channel 使用指南
android·kotlin·协程
草字2 小时前
cocos 打包安卓
android
DeBuggggggg3 小时前
centos 7.6安装mysql8
android
浩浩测试一下4 小时前
渗透信息收集- Web应用漏洞与指纹信息收集以及情报收集
android·前端·安全·web安全·网络安全·安全架构
移动开发者1号5 小时前
深入理解原子类与CAS无锁编程:原理、实战与优化
android·kotlin
陈卓4105 小时前
MySQL-主从复制&分库分表
android·mysql·adb
移动开发者1号5 小时前
深入理解 ThreadLocal:原理、实战与优化指南
android·kotlin
zhangphil5 小时前
Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算
android
厦门德仔6 小时前
【WPF】WPF(样式)
android·java·wpf