1. 为什么需要 ViewModel:生命周期问题、配置改变、内存泄漏、数据持久化需求

Android 应用组件(Activity / Fragment)的生命周期不受开发者直接控制。旋转屏幕、切换语言、进入多窗口模式等配置改变会导致 Activity 重建,而普通成员变量在重建时全部丢失。同时,在异步回调中持有 Activity 引用极易造成内存泄漏。这些问题催生了 ViewModel——一个专为跨越生命周期存储界面相关数据而设计的架构组件。

1.1 四个核心痛点

痛点 典型场景 后果
生命周期割裂 Activity 的 onCreate 中加载数据,onDestroy 时销毁 每次重建都需要重新加载,产生不必要的网络/数据库请求
配置改变 横竖屏旋转、分辨率变更、夜间模式切换 Activity 销毁重建,临时数据全部清空
内存泄漏 匿名内部类 / 异步回调持有 Activity 引用 Activity 无法被 GC 回收,OOM 风险上升
数据持久化缺失 用户填写表单时接听电话,返回 App 未保存的表单数据丢失,用户体验极差

1.2 配置改变带来的 Activity 重建流程

下面这张 生命周期对比图 展示了在配置改变时,没有 ViewModel 与使用 ViewModel 的处理差异。注意 onSaveInstanceState 只能存储少量序列化数据,不适合保存列表、位图等较大对象。

配置改变 → Activity 重建对比(无 ViewModel / 有 ViewModel) ❌ 无 ViewModel Activity 运行(横屏) 配置改变(旋转) onDestroy(数据丢失) onCreate(重新加载) 网络请求 / 数据库查询重复执行 ✅ 有 ViewModel Activity 运行(横屏) 配置改变(旋转) Activity 重建 ViewModel 存活(数据保留) Activity onCreated 数据直接从 ViewModel 获取,零重复请求

1.3 内存泄漏的典型错误代码

下面这段代码展示了在异步回调中直接使用 Activity 引用导致的泄漏风险。当 Activity 已经销毁而回调尚未执行时,整个 Activity 实例无法被回收。

// ❌ 错误写法:匿名内部类隐式持有 Activity 引用
public class MainActivity extends AppCompatActivity {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.text);

        // 模拟网络请求回调
        NetworkManager.fetchData(new Callback() {
            @Override
            public void onSuccess(String data) {
                // 此时若 Activity 已销毁,引用仍被持有 → 内存泄漏
                mTextView.setText(data);
            }
        });
    }
}
ViewModel 解决思路:将数据获取逻辑从 Activity 剥离到 ViewModel,Activity 仅负责订阅。即使 Activity 重建,ViewModel 实例仍然存活,回调不会持有已销毁的 Activity 引用,从根本上阻断内存泄漏。

1.4 数据持久化需求 vs ViewModel 的职责边界

需要注意的是,ViewModel 不直接替代持久化存储。它保存的是内存级数据,在进程被系统杀死后仍然会丢失。真正的持久化需求(保存到磁盘、数据库、SharedPreferences)应交由 Room、DataStore 或 SavedStateHandle 处理。ViewModel 配合 SavedStateHandle 可以在进程被 kill 后自动恢复部分状态,这是后续章节的重点。

常见误解:认为 ViewModel 可以永久保存所有数据。事实上,ViewModel 只在当前进程存活期间有效。一旦进程被系统回收,所有 ViewModel 实例跟随销毁。如果应用需要跨进程存活的数据,必须使用持久化方案(如 Room、DataStore)。

1.5 ViewModel 的生命周期范围

准确理解 ViewModel 的生命周期边界是正确使用的前提。下面这张表总结了 ViewModel 的存活范围与常见反例:

场景 ViewModel 存活 ViewModel 销毁
Activity 正常旋转(配置改变) ✅ 存活 —
Activity 正常返回(finish) — ✅ 销毁
Fragment 替换但宿主 Activity 未销毁 ✅ 存活(Fragment 级别的 ViewModel 仍保留) —
进程被系统杀死(低内存) — ✅ 销毁(可借助 SavedStateHandle 恢复)
开发者手动调用 finish() — ✅ 销毁

理解这些边界后,你就能明确哪些数据应放入 ViewModel,哪些应存入持久层。ViewModel 的核心价值是在配置改变时无痛保留数据,同时通过解耦 Activity 引用解决内存泄漏问题。接下来的章节将逐步讲解 ViewModel 的创建、使用、测试与进阶技巧。