做网站公司怎么赚钱如何用电子邮箱做网站
Android 的 ViewModel 是 Jetpack 架构组件库的核心部分,旨在以生命周期感知的方式存储和管理与 UI 相关的数据。它的核心目标是解决两大痛点:
- 数据持久化: 在配置变更(如屏幕旋转、语言切换、多窗口模式切换)时保留数据,避免重新加载数据造成的资源浪费和用户体验中断。
- 职责分离: 将 UI 控制器(
Activity/Fragment)与数据操作逻辑分离,使代码更清晰、可测试性更强。
核心机制与原理详解
-
设计目标与核心思想:
- 生命周期感知:
ViewModel对象的生命周期比其关联的 UI 控制器(Activity/Fragment)更长。它从 UI 控制器创建开始,直到其关联的 UI 控制器永久销毁(Activityfinish()或Fragment分离且不再附加)时才被销毁。这意味着配置变更导致的临时销毁与重建不会影响ViewModel。 - 数据持有者: 主要负责持有、准备和管理 UI 所需的数据。它可以执行数据获取(如从数据库、网络)、转换、聚合等操作。
- UI 控制器解耦: UI 控制器(
Activity/Fragment)负责显示数据和响应用户交互,ViewModel负责提供数据和处理业务逻辑。两者通过观察(如LiveData)或直接调用接口进行通信。
- 生命周期感知:
-
创建过程:
- 入口点: 通常使用
ViewModelProvider来获取ViewModel实例。
// 在 Activity 中 val viewModel = ViewModelProvider(this).get(MyViewModel::class.java) // 在 Fragment 中 (推荐使用 activityViewModels 或 viewModels) val viewModel: MyViewModel by viewModels() val sharedViewModel: SharedViewModel by activityViewModels()- 关键参数 -
ViewModelStoreOwner:ViewModelProvider的构造函数需要一个ViewModelStoreOwner。ComponentActivity(AppCompatActivity 的基类) 和Fragment都实现了这个接口。它提供了访问ViewModelStore的能力。 ViewModelProvider的作用:- 检查
ViewModelStore中是否已存在请求类型的ViewModel实例。 - 如果存在,直接返回该实例。
- 如果不存在,则通过
Factory(默认为NewInstanceFactory或AndroidViewModelFactory)创建新实例,并将其存储在ViewModelStore中,然后返回。
- 检查
- 入口点: 通常使用
-
存储与作用域 -
ViewModelStore:- 核心容器: 每个
ViewModelStoreOwner(如一个Activity或一个特定Fragment)内部都维护着一个ViewModelStore。它是一个简单的容器类(通常是HashMap<String, ViewModel>),负责存储与该作用域关联的所有ViewModel实例。 - 键 (Key):
ViewModel在ViewModelStore中的存储键通常是其类名(如"com.example.MyViewModel")。当使用带Factory的特定键时(如为同一类型创建多个实例),键会更复杂。 - 配置变更下的存活: 当配置变更发生时,系统销毁并重建 UI 控制器 (
Activity/Fragment)。但是,系统会将ViewModelStore对象保留在内存中。重建后的新 UI 控制器实例会重新附加到同一个ViewModelStore。因此,ViewModelProvider能在新 UI 控制器中检索到之前创建的ViewModel实例。 - 永久销毁: 当 UI 控制器真正结束其生命周期(用户按返回键、调用
finish()或Fragment被永久移除),系统会调用ViewModelStore的clear()方法。该方法会遍历所有存储的ViewModel实例,调用它们的onCleared()方法(用于释放资源,如取消异步任务),然后清空 Map。之后,ViewModelStore及其包含的ViewModel实例会被垃圾回收。
- 核心容器: 每个
-
与生命周期的绑定 -
Lifecycle:- 自动关联: 当你通过
ViewModelProvider(owner)创建ViewModel时,该ViewModel就自动与owner(ViewModelStoreOwner) 的生命周期关联起来了。 onCleared()钩子:ViewModel类提供了一个onCleared()方法。当关联的ViewModelStore被clear()时(即 UI 控制器永久销毁时),框架会自动调用这个方法。开发者可以重写此方法来清理资源(如取消正在进行的网络请求、关闭数据库连接、移除监听器等)。这是ViewModel感知其“结束”生命周期的关键点。
- 自动关联: 当你通过
-
数据通信 (通常结合
LiveData):- 最佳搭档: 虽然
ViewModel可以包含任何数据,但LiveData是其推荐的用于向 UI 暴露数据的方式。 - 机制:
ViewModel内部持有LiveData对象(通常是MutableLiveData私有,暴露为LiveData公有)。UI 控制器 (Activity/Fragment) 在onCreate()或onViewCreated()中观察这些LiveData。 - 优势:
- 生命周期感知订阅:
LiveData自动管理订阅,确保只在 UI 控制器处于活跃状态 (STARTED或RESUMED) 时才更新 UI,避免在后台更新导致的崩溃或资源浪费。 - 数据更新:
ViewModel中的业务逻辑(如响应按钮点击的网络请求)完成后,通过更新MutableLiveData的值来触发LiveData通知观察者(UI 控制器)。 - 配置变更无缝衔接: 由于
ViewModel和LiveData在配置变更后存活,新的 UI 控制器重新观察同一个LiveData时,会立即收到最后一次保存的数据,从而实现无缝恢复。
- 生命周期感知订阅:
- 最佳搭档: 虽然
-
作用域扩展 (
SavedStateHandle):- 需求: 基本
ViewModel在进程被系统杀死后重建时,其内部数据也会丢失。需要一种机制在进程死亡后恢复少量关键 UI 状态(如列表滚动位置、输入框临时内容)。 - 解决方案:
ViewModel库提供了SavedStateHandle作为ViewModel构造函数的参数。 - 原理:
- 当使用
SavedStateHandle时,ViewModel的创建工厂(如AbstractSavedStateViewModelFactory)会负责将SavedStateHandle注入到ViewModel中。 SavedStateHandle本质上是一个键值对容器 (Map<String, Any?>)。它利用底层Activity的onSaveInstanceState(Bundle)机制。- 在 UI 控制器临时销毁(配置变更)或可能永久销毁(进程回收)前,
SavedStateHandle中的数据会被序列化到Bundle中。 - 在 UI 控制器重建后,
Bundle中的数据会被反序列化回SavedStateHandle。这样,即使在进程被杀死后重建,ViewModel也能通过SavedStateHandle恢复那些关键状态。
- 当使用
- 使用:
class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {val someState: MutableStateFlow<String> = savedStateHandle.getStateFlow("key", "")// 或者使用 LiveDataval liveDataState: LiveData<String> = savedStateHandle.getLiveData("key")fun updateState(newValue: String) {savedStateHandle["key"] = newValue // 自动触发保存} } // 创建时需要使用 SavedStateViewModelFactory 或 by viewModels() 自动处理
- 需求: 基本
-
Fragment 间共享数据:
- 场景: 同一个
Activity下的多个Fragment需要共享数据(如购物车、用户资料)。 - 实现: 让这些
Fragment使用 同一个作用域 的ViewModelStoreOwner。通常,这个共享的作用域就是它们所属的Activity。 - 方法: 在
Fragment中,使用activityViewModels()委托或ViewModelProvider(requireActivity())来获取ViewModel实例。 - 原理: 所有通过该
Activity作用域 (ViewModelStoreOwner) 获取的同一类型的ViewModel(使用默认 Key),返回的都是同一个实例。因此,不同的Fragment访问的是同一个ViewModel对象,自然就实现了数据共享和通信。
- 场景: 同一个
-
底层关键类与交互:
ViewModel: 开发者继承的基类,包含数据和逻辑,有onCleared()钩子。ViewModelStoreOwner: 接口(ComponentActivity,Fragment实现),提供getViewModelStore()方法。ViewModelStore: 内部维护一个Map<String, ViewModel>,负责存储和清理ViewModel。ViewModelProvider: 工厂类,负责从ViewModelStore获取或创建ViewModel实例。ViewModelProvider.Factory: 接口,用于创建ViewModel实例(支持带参数构造函数)。SavedStateHandle: 用于在进程死亡后恢复少量状态的辅助类。ComponentActivity: 实现了ViewModelStoreOwner和HasDefaultViewModelProviderFactory,在其onRetainNonConfigurationInstance()中保存ViewModelStore,在onCreate()中恢复。在其onDestroy()中判断是否为配置变更决定是否调用ViewModelStore.clear()。FragmentManagerViewModel: (Fragment 作用域实现的关键) 一个特殊的ViewModel,由FragmentManager持有,用于管理Fragment作用域的ViewModelStore以及嵌套Fragment的作用域关系。
-
重要注意事项:
- 绝不持有 View/Activity Context 引用:
ViewModel生命周期可能比Activity长。如果持有Activity引用,会导致Activity无法被回收,造成内存泄漏。如果需要Application Context,使用AndroidViewModel(它持有Application引用,Application生命周期等同于进程)。 - 轻量级状态恢复:
SavedStateHandle用于恢复少量、序列化/反序列化快的 UI 相关状态。不要用它存储大量数据或复杂对象。大数据应持久化到数据库或网络。 - 异步操作: 在
ViewModel中启动的异步操作(如协程、LiveData转换),必须在onCleared()中取消或清理,防止内存泄漏和无效更新。 - 测试友好: 由于
ViewModel不依赖 Android 框架的具体 UI,它们可以非常方便地在 JUnit 测试中进行单元测试。
- 绝不持有 View/Activity Context 引用:
总结流程图
(配置变更 / 进程重建)|v
+-------------------+
| UI Controller | (Activity/Fragment) 销毁或重建
| (onDestroy) | --(永久销毁?)--> Yes -> [调用 ViewModelStore.clear()] -> [触发 ViewModel.onCleared()]
| | --(配置变更?)--> Yes -> [系统保留 ViewModelStore]
+-------------------+|| (重建后)v
+-------------------+
| UI Controller | (新的 Activity/Fragment 实例)
| (onCreate) | --[创建 ViewModelProvider] --> [请求 ViewModel]
+-------------------+|v
+-------------------+
| ViewModelProvider | --[检查 ViewModelStore] --> [存在?] -> Yes -> 返回现有实例
| | --> No -> [使用 Factory 创建新实例] -> [存入 ViewModelStore] -> 返回实例
+-------------------+|v
+-------------------+
| ViewModel | --[持有 LiveData/SavedStateHandle] --> [提供数据/处理逻辑]
| | <--[观察 LiveData / 调用方法]------- UI Controller
+-------------------+|v
(UI 显示数据/响应用户交互)
ViewModel 的核心在于 ViewModelStore 在配置变更中的持久性,以及其生命周期与 UI 控制器的解耦(存活至永久销毁)。结合 LiveData 的生命周期感知数据观察和 SavedStateHandle 的轻量级状态持久化,它构成了 Android 现代、健壮、可测试的 UI 架构基石。理解 ViewModelStoreOwner、ViewModelStore 和 ViewModelProvider 的协作机制是掌握其底层原理的关键。
