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

相关推荐
移动开发者1号4 分钟前
新建Android项目build.gradle不是以前熟悉的配置
android
tangweiguo030519872 小时前
Android Kotlin AIDL 完整实现与优化指南
android·kotlin
思想觉悟2 小时前
使用AndroidStudio阅读源码
android
智驾3 小时前
HarmonyOS 是 Android 套壳嘛?
android·harmonyos·替代·套壳
longzekai3 小时前
【重学Android】03.高版本 Android Studio 不能使用引用库资源ID的问题
android·ide·android studio
YSoup3 小时前
2025深圳中兴通讯安卓开发社招面经
android
声知视界4 小时前
音视频基础能力之 Android 音频篇 (六):音频编解码到底哪家强?
android·音视频开发
ufo00l4 小时前
讲述EventBus和RxBus的工作模式以及和LiveData消息总栈的优劣势
android
玄之宵4 小时前
Android 回显
android·java·开发语言