一文读懂 ViewModel

一、核心作用(解决的核心问题)

ViewModel 是 Android 架构组件的核心,核心目标是分离 UI 控制器(Activity/Fragment)与数据逻辑,并解决「配置变更(如横竖屏切换)时数据丢失」的问题。

二、为什么需要 ViewModel?(onSaveInstanceState 的局限性)

以往通过 onSaveInstanceState + Bundle 保存状态存在明显缺陷(仅适用于轻量序列化数据),核心原因:

  1. 设计定位问题onSaveInstanceState 仅用于临时状态恢复(如旋转、内存不足回收),非持久化;且运行在主线程,若允许存储大量数据会导致 Activity 销毁耗时。
  2. 数据类型限制:Bundle 底层仅支持有限的可序列化类型,无法存储复杂数据。
  3. 性能开销:序列化 / 反序列化过程有额外性能损耗(Bundle 是跨进程通信载体,Activity 状态需通过 Binder 传递给系统进程暂存)。

三、ViewModel 核心能力

  1. 配置变更时保留状态:常见配置变更(横竖屏切换、分辨率调整、权限变更、系统字体样式变更)后,ViewModel 仍持有原有数据,无需重新加载。
  2. MVVM 架构解耦核心:ViewModel 不持有 View/Activity 引用,仅暴露数据和业务方法,实现 View 与 ViewModel 完全解耦。
  3. 生命周期感知:感知 UI Controller(Activity/Fragment)的生命周期,UI 重建后仍能获取同一个 ViewModel 实例;UI 真正销毁时自动释放资源。

四、ViewModel 具体使用

1. 基础使用(无参构造)

步骤 1:定义 ViewModel 类(继承 ViewModel)

scala 复制代码
// MyViewModel.java
public class MyViewModel extends ViewModel {
   // 存储需要跨配置变更保留的数据
   public int myInt = 0;
}

步骤 2:UI Controller 中绑定 ViewModel

scss 复制代码
// MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   // 绑定ViewModel到当前Activity(核心:ViewModelProvider(this))
   MyViewModel mViewModel = new ViewModelProvider(this).get(MyViewModel.class);
    // 后续可直接操作mViewModel中的数据
}

2. 进阶使用(带参构造:自定义 Factory)

ViewModelProviders 默认使用无参构造,若需传入参数(如数据库实例),需实现 ViewModelProvider.Factory 接口:

步骤 1:实现 Factory 类

java 复制代码
// MyViewModelFactory.java
public class MyViewModelFactory implements ViewModelProvider.Factory {
   // 需传入的依赖(如数据库、仓库等)
   private AppDatabase mAppDatabase;

   // 构造函数接收依赖
   public MyViewModelFactory(AppDatabase appDatabase) {
       mAppDatabase = appDatabase;
   }

   // 重写create方法,创建带参ViewModel实例
   @Override
   public <T extends ViewModel> T create(Class<T> modelClass) {
       return (T) new MyViewModel(mAppDatabase);
   }
}

步骤 2:定义带参 ViewModel

scala 复制代码
public class MyViewModel extends ViewModel {
   // 带参构造
   public MyViewModel(AppDatabase appDatabase) {
       // 初始化业务逻辑(如初始化仓库、数据请求等)
   }
}

步骤 3:使用 Factory 创建 ViewModel

scss 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 1. 创建Factory实例,传入依赖
    MyViewModelFactory factory = new MyViewModelFactory(database);
    // 2. 通过Factory创建带参ViewModel
    MyViewModel viewModel = new ViewModelProvider(this, factory).get(MyViewModel.class);
}

3. 扩展场景:Fragment 间数据共享

通过传入 getActivity() 让多个 Fragment 共享同一个 ViewModel 实例,实现 Fragment 间通信:

csharp 复制代码
// Fragment 中获取与宿主Activity同生命周期的ViewModel
// Activity scope --- 多个Fragment共享,用于跨Fragment通信
FragmentCommunicationViewModel mCommunicationViewModel = 
    new ViewModelProvider(getActivity()).get(FragmentCommunicationViewModel.class);

五、ViewModel 生命周期 & 注意事项

1. 存活时间(取决于绑定的 ViewModelStoreOwner)

表格

绑定对象 存活周期 适用场景
Activity(this) 存活至 Activity finish()(配置变更的 onDestroy 不销毁) Activity 内数据跨配置变更保留
Fragment(this) 存活至 Fragment 被移除 Fragment 自身私有数据
Fragment(getActivity()) 与宿主 Activity 同生命周期 多 Fragment 间数据共享

2. 唯一生命周期回调:onCleared ()

  • onCleared() 是 ViewModel 唯一的生命周期回调方法;
  • 触发时机:ViewModel 绑定的 Owner(Activity/Fragment)真正销毁时(如 Activity finish ()、Fragment 被移除);
  • 用途:释放资源(如取消网络请求、关闭数据库连接),避免内存泄漏。

3. 核心注意事项(必看)

禁止在 ViewModel 中持有 UI Controller(Activity/Fragment)或 Context :ViewModel 寿命长于 UI Controller,持有引用会导致 UI 组件无法被 GC 回收,引发内存泄漏。✅ 若需 Context,可使用 AndroidViewModel(继承 ViewModel,持有 Application 级 Context,生命周期与应用一致)。

核心使用示例总结

csharp 复制代码
// 1. Activity 私有(同Activity生命周期)
new ViewModelProvider(this).get(MmsTabViewModel.class);

// 2. 多Fragment共享(宿主Activity生命周期)
new ViewModelProvider(getActivity()).get(FragmentCommunicationViewModel.class);

// 3. Fragment 私有(同Fragment生命周期)
new ViewModelProvider(this).get(ConversationBaseViewModel.class);

总结

  1. ViewModel 核心解决「配置变更数据丢失」和「UI 与数据逻辑解耦」问题,替代 onSaveInstanceState 处理非轻量数据;
  2. ViewModel 存活周期由绑定的 ViewModelStoreOwner 决定,onCleared() 是唯一资源释放入口;
  3. 严禁持有 UI/Context 引用,带参构造需通过自定义 Factory 实现,多 Fragment 通信可绑定 Activity 级 ViewModel。
相关推荐
alexhilton2 分钟前
面向Android开发者的Google I/O 2026
android·kotlin·android jetpack
私人珍藏库18 分钟前
【Android】豆图助手-永久HY-模拟微X~zfb各种截图
android·app·工具·软件·多功能
程序员陆业聪2 小时前
Shadow实战接入与生产落地:从零搭建到稳定运行
android
程序员陆业聪2 小时前
Shadow Transform:编译期的魔法——字节码替换实战
android
imuliuliang6 小时前
Laravel6.x核心特性全解析
android·php·laravel
idingzhi7 小时前
A股量化策略日报(2026年05月22日)
android·开发语言·python·kotlin
测试员周周7 小时前
【Appium 系列】第14节-断言与验证 — Validator 的设计
android·人工智能·python·功能测试·ios·单元测试·appium
赏金术士8 小时前
Android 动画对比指南:View 系统 vs Jetpack Compose
android·kotlin·compose
我命由我123459 小时前
C++ - 面向对象 - 析构函数
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
失眠的咕噜9 小时前
PDA 安卓设备上传多张图片
android·前端·javascript