一、核心作用(解决的核心问题)
ViewModel 是 Android 架构组件的核心,核心目标是分离 UI 控制器(Activity/Fragment)与数据逻辑,并解决「配置变更(如横竖屏切换)时数据丢失」的问题。
二、为什么需要 ViewModel?(onSaveInstanceState 的局限性)
以往通过 onSaveInstanceState + Bundle 保存状态存在明显缺陷(仅适用于轻量序列化数据),核心原因:
- 设计定位问题 :
onSaveInstanceState仅用于临时状态恢复(如旋转、内存不足回收),非持久化;且运行在主线程,若允许存储大量数据会导致 Activity 销毁耗时。 - 数据类型限制:Bundle 底层仅支持有限的可序列化类型,无法存储复杂数据。
- 性能开销:序列化 / 反序列化过程有额外性能损耗(Bundle 是跨进程通信载体,Activity 状态需通过 Binder 传递给系统进程暂存)。
三、ViewModel 核心能力
- 配置变更时保留状态:常见配置变更(横竖屏切换、分辨率调整、权限变更、系统字体样式变更)后,ViewModel 仍持有原有数据,无需重新加载。
- MVVM 架构解耦核心:ViewModel 不持有 View/Activity 引用,仅暴露数据和业务方法,实现 View 与 ViewModel 完全解耦。
- 生命周期感知:感知 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);
总结
- ViewModel 核心解决「配置变更数据丢失」和「UI 与数据逻辑解耦」问题,替代
onSaveInstanceState处理非轻量数据; - ViewModel 存活周期由绑定的
ViewModelStoreOwner决定,onCleared()是唯一资源释放入口; - 严禁持有 UI/Context 引用,带参构造需通过自定义 Factory 实现,多 Fragment 通信可绑定 Activity 级 ViewModel。