Jetpack之ViewModel
The ViewModel class is a business logic or screen level state holder.
上面是官方给的定义,ViewModel 类是业务逻辑或屏幕级状态持有者。
一、业务逻辑持有者
在此之前,无论是MVC模式,还是MVP模式,在视图层,都会产生对业务逻辑层的依赖,从而导致出现内存泄漏的情况。那ViewModel又是如何处理业务逻辑层和视图层的依赖,从而避免了常见的内存泄漏的问题的呢?

依赖Lifecycle对宿主生命周期的感知,处理对Viewmodel的依赖
1.1、应用
NormalViewModel
package com.anniljing.viewmodelcorestudy;import android.app.Application;import java.util.ArrayList;
import java.util.List;import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;public class NormalViewModel extends AndroidViewModel {public NormalViewModel(@NonNull Application application) {super(application);}public List<Integer> getdatas() {List<Integer> data = new ArrayList<>();for (int i = 0; i < 10; i++) {data.add(i);}return data;}
}
NormalActivity
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;import com.anniljing.viewmodelcorestudy.databinding.ActivityNormalBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class NormalActivity extends AppCompatActivity {private ActivityNormalBinding mBinding;private NormalViewModel mViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityNormalBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mViewModel = new ViewModelProvider(this).get(NormalViewModel.class);}
}
ComponentActivity源码
getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}}}});
此处在Activity中Lifecycle的ON_DESTROY事件中,清除了ViewModel。
1.2、源码解析

1.2.1 创建ViewModelStore
public ComponentActivity() {Lifecycle lifecycle = getLifecycle();//noinspection ConstantConditionsif (lifecycle == null) {throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "+ "constructor. Please make sure you are lazily constructing your Lifecycle "+ "in the first call to getLifecycle() rather than relying on field "+ "initialization.");}getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}}}});getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {ensureViewModelStore();getLifecycle().removeObserver(this);}});}
在ComponentActivity的构造方法中,注册了多个Lifecycle的观察者,其中有两个涉及ViewModelStore的,一个是收到宿主的生命周期事件后,就创建了ViewModelStore,随后就移除了该观察者;另一个则是监听到宿主的ON_DESTROY事件后,清空ViewModelStore的ViewModel
1.2.2、创建Factory
1.2.2.1、创建ViewModel的时候,第一步我们创建了ViewModelProvider,调用了其中一个构造方法
public constructor(owner: ViewModelStoreOwner) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
1.2.2.2、ViewModelProvider的构造方法中,调用了默认的Factory
public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instanceinternal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"}
1.2.2.3、由于ComponentActivity实现了HasDefaultViewModelProviderFactory接口,所以Factory的实际对象是SavedStateViewModelFactory
@NonNull@Overridepublic ViewModelProvider.Factory getDefaultViewModelProviderFactory() {if (mDefaultFactory == null) {mDefaultFactory = new SavedStateViewModelFactory(getApplication(),this,getIntent() != null ? getIntent().getExtras() : null);}return mDefaultFactory;}
1.2.3、创建ViewModel
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {val viewModel = store[key]if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel)return viewModel as T} else {@Suppress("ControlFlowWithEmptyBody")if (viewModel != null) {// TODO: log a warning.}}val extras = MutableCreationExtras(defaultCreationExtras)extras[VIEW_MODEL_KEY] = key// AGP has some desugaring issues associated with compileOnly dependencies so we need to// fall back to the other create method to keep from crashing.return try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}
应用层通过ViewModelProvider的get方法创建ViewModel,并且保存到ViewModelStore中。
二、屏幕状态的持有者
该功能主要处理当设备配置发生变化时,界面会重新绘制,导致数据丢失的问题。

屏幕发生旋转的时候,会调用onDestroy方法,界面会重新绘制。
2.1、ViewModel之前
2.1.1、manifest中配置

在activity里面的configChanges属性里面配置orientation|screenSize,则屏幕旋转的时候,界面就不会重新绘制。
2.1.2、onSaveInstanceState和onRestoreInstanceState
如果manifest里面没有配置configChanges,则屏幕旋转的时候,在onDestroy之前会调用onSaveInstanceState,在恢复界面的时候,会调用onRestoreInstanceState,这样我们就可以在以上两个方法中做保存和恢复数据的逻辑。
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private NormalState mNormalState;private static final String KEY="NormalState";private String saveString="";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");if (savedInstanceState !=null){saveString=savedInstanceState.getString(KEY,"");}mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mNormalState = new NormalState();mNormalState.setString(saveString);Log.e(TAG, mNormalState.getString());mBinding.tvState.setOnClickListener((view) -> {mNormalState.setString("NormalState");Log.e(TAG,"Click after:"+ mNormalState.getString());});}@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);Log.e(TAG, "onSaveInstanceState");outState.putString(KEY,"NormalState");}@Overrideprotected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);Log.e(TAG, "onRestoreInstanceState");}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy");}
}
保存数据:

重新绘制的时候,取出数据:


在onSaveInstanceState里面增加保存逻辑,在onCreate方法里面就可以恢复以前的数据了。
2.2、 使用ViewModel
ViewModelSaveState:
package com.anniljing.viewmodelcorestudy;import android.app.Application;import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;public class ViewModelSaveState extends AndroidViewModel {private String mString;public ViewModelSaveState(@NonNull Application application) {super(application);}public String getString() {return mString;}public void setString(String string) {mString = string;}
}
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private ViewModelSaveState mViewModelSaveState;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mViewModelSaveState = new ViewModelProvider(this).get(ViewModelSaveState.class);Log.e(TAG,"Before click:"+mViewModelSaveState.getString());mBinding.tvState.setOnClickListener((view) -> {mViewModelSaveState.setString("ViewModelState");Log.e(TAG, "Click after:" + mViewModelSaveState.getString());});}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG,"onDestroy");}
}

可以看到,引入ViewModel以后,不需要在onSaveInstanceState方法中增加额外的保存逻辑,重绘后就可以恢复以前的数据。
无论是ViewModel,还是重写onSaveInstanceState方法,当内存有限导致界面退出重绘时,就无法恢复以前的数据了。
我们可以通过以下操作来模拟内存不足时,导致应用杀死的效果:
1、启用开发者模式
2、打开“不保留活动”
3、打开应用后,按home键,退出应用
4、重新打开应用。

2.3、使用SavedStateHandle
ViewModelWithHandleSaveState
package com.anniljing.viewmodelcorestudy;import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;public class ViewModelWithHandleSaveState extends ViewModel {private static final String KEY = "ViewModelWithHandleSaveState";private SavedStateHandle mStateHandle;public ViewModelWithHandleSaveState(SavedStateHandle stateHandle) {mStateHandle = stateHandle;}public MutableLiveData<String> getLiveData() {return mStateHandle.getLiveData(KEY);}
}
1、构造方法里面添加SavedStateHandle参数。
2、获取的时候通过mStateHandle。
SaveStateActivity
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private ViewModelWithHandleSaveState mWithHandleSaveState;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mWithHandleSaveState = new ViewModelProvider(this).get(ViewModelWithHandleSaveState.class);Log.e(TAG, "Before click:" + mWithHandleSaveState.getLiveData().getValue());mWithHandleSaveState.getLiveData().observe(this, s -> {Log.e(TAG, "After click:" + mWithHandleSaveState.getLiveData().getValue());});mBinding.tvState.setOnClickListener((view) -> mWithHandleSaveState.getLiveData().postValue("ViewModelWithHandleSaveState"));}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy");}
}

相关文章:
Jetpack之ViewModel
The ViewModel class is a business logic or screen level state holder. 上面是官方给的定义,ViewModel 类是业务逻辑或屏幕级状态持有者。 一、业务逻辑持有者 在此之前,无论是MVC模式,还是MVP模式,在视图层,都会…...
追梦之旅【数据结构篇】——详解C语言动态实现顺序表
详解C语言动态实现顺序表~😎前言🙌顺序表概念及结构🙌功能函数的具体实现分析:🙌尾插函数具体实现:尾删函数具体实现:头插函数具体实现:头删插函数具体实现:任意插函数具…...
xss基础
目录标题一、XSS的原理二、XSS漏洞分类1、反射型xss2、存储型XSS3、基于DOM的XSS三、XSS漏洞的危害及验证四、XSS漏洞的黑盒测试五、XSS漏洞的白盒测试一、XSS的原理 跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表(…...
移动WEB开发二、流式布局
零、文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789个人博客-GiteePages:https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee:https://gitee.com/bluecusliyou/TechLearnGithub:https:…...
分享在线预约系统制作步骤_在线预约链接怎么做
在微信小程序上进行在线预约,不管是商家还是顾客,都可以自由选择时间,顾客还可以通过预约小程序,了解到所选服务的详情和功能特色,不必等到去店内听介绍,顾客能节省等候时间,商家能解放招待人力…...
【每日一题Day125】LC1326灌溉花园的最少水龙头数目 | 动态规划 贪心
灌溉花园的最少水龙头数目【LC1326】 在 x 轴上有一个一维的花园。花园长度为 n,从点 0 开始,到点 n 结束。 花园里总共有 n 1 个水龙头,分别位于 [0, 1, ..., n] 。 给你一个整数 n 和一个长度为 n 1 的整数数组 ranges ,其中 …...
C# FFmpeg推流Vlc.DotNet拉流优化参数
FFmpeg是流媒体开源神器,视频转换、剪裁包括推流,无所不能,很多系统都是基于其开发的。拉流可以用FFplay,但是不利于集成到自己的代码中,因此拉流选择了Vlc.DotNet。 在使用中,仅使用默认参数,…...
pnpm v8版本升级变化关注点(前瞻速攻版)
前言 pnpm v8.0.0-alpha.0 版本已经发布,包含少量变化,但其中还是有令人在意的点的。 本文将默认读者拥有大部分 pnpm v7 版本的知识储备,进行 v8 版本的前瞻速攻。 安装方法 目前通过指定 Tag 方式可以安装 v8 alpha 版: npm…...
Python基础-环境安装
Python安装1.下载PythonPython网址:https://www.python.org/进入Python官网,点击Downloads,选择自己对应的操作系统(此处以Windows为例)在左侧的稳定发行版中,选择一个3.5版本以上的,然后点击对…...
重载、重写、重构概念辨析
首先,重载、重写、重构都表现为方法名相同 重载 重载(overload),表示同一类的方法之间的关系,至少有以下其中一种情况 参数个数不同参数类型不同参数顺序不同 注意,返回值类型不同不能作为重载依据 重…...
第九章 - 多表查询(join,left join 等)与合并查询(union union all)
第九章 - 多表查询(join,left join 等)与合并查询(union)交叉链接(笛卡尔积)内连接查询外连接查询左链接: left join右链接:right join组合查询 union & union all使…...
matplotlib学习笔记(持续更新中…)
目录 1. 安装,导入 2. figure,axes(图形,坐标图形) 2.1 figure对象 2.2 axes对象 2.3 代码演示 2.3 subplot() 方法 3. 图表的导出 3.1 savefig() 方法 3.2 代码演示 1. 安装,导入 pip install m…...
STM32 SystemInit()函数学习总结
拿到程序后如何看系统时钟?User文件夹——system_stm32f4xx程序,先找systemcoreclock(系统时钟)但是这里这么多个系统时钟应该如何选择?点击魔法棒,然后点击C/C可以看到define的是F40_41XXX.USE这一款 ,对应着就找出了…...
【Spring Boot 原理分析】- 自动配置
【Spring Boot 原理分析】- 自动配置 Condition 注解 Condition 是 Spring 4.0 增加的条件判断功能,通过这个功能可以实现选择的创建 Bean 操作 👑 我们在使用 Spring 的时候,只需导入某个依赖的坐标,就可以直接通过 Autwired 注…...
简明易懂的JVM理解
文章目录简明易懂的JVM和GC理解写在前面Java虚拟机(JVM)的组成基本介绍结构类加载子系统(ClassLoader SubSystem)介绍类加载过程类加载过程小结双亲委派模型(Parent-Delegation Model)简介优点Java9的类加载的委派关系变动双亲委派模型小结运行时数据区(Runtime Data Areas)介绍…...
新考纲下的PMP考试有多难?
PMP考试在6月25号考试结束后,在网上引起一片哗然,新考纲领域与考点的转变使得考试难度加大:PMP考试敏捷和混合内容比重大,考试难度加大很多;考题更加注重考生的知识应用能力,领域更宽; 接下来我…...
朗润国际期货:知名投行/大佬打Call记
知名投行/大佬打Call记 2023年知名投行/大佬看好哪些投资标的 中国股市 高盛(2023年1月):将上涨15% 花旗(2023年1月):上半年会成为投资两点 摩根大通(2022年11月):M…...
遗传算法及Python实现
0 建议学时 4学时 1 人工智能概述 2020中国人工智能产业年会在苏州召开,会上发布的《中国人工智能发展报告2020》显示,过去十年(2011-2020) ,中国人工智能专利申请量达389571件,占全球总量的74.7%,位居世界第一。 报…...
零基础 Ubuntu 20.04.01 下搭建51单片机开发环境[开源编译器SDCC]
原创首发于CSDN,转载请注明出处,谢谢! 文章目录为何会在Linux下开发单片机个人系统环境与所用开发板安装开源编译器 sdccSTC MCU ISP 闪存工具 stcgal 的安装单片机代码的编译与测试|编写主代码 main.c|使用 sdcc 编译…...
手摸手快速入门 正则表达式 (Vue源码中的使用)
vue2源码 在 vue2 源码的 src\compiler\parser\html-parser.js 文件中 里面有大量的正则表达式,如下图 可以看到非常的长,不是我说,就前几行,如果没有相关的 正则表达式 的工具,我可能就被劝退了😭 这里…...
Phi-3-mini-gguf辅助C语言学习:从指针理解到项目实战
Phi-3-mini-gguf辅助C语言学习:从指针理解到项目实战 1. 为什么选择AI辅助学习C语言 学习C语言就像学骑自行车,刚开始总会摇摇晃晃,特别是遇到指针和内存管理这些概念时,很容易"摔跟头"。传统的学习方式往往需要反复查…...
Pixiv -直连-手机电脑全平台可用,聚合多个资源一站搞定
功能特点 全平台支持:兼容 Android、iOS、Windows 和 macOS 系统,覆盖主流设备。直连访问:内置优化网络链路,绕过访问限制,无需额外配置或登录即可加载内容。无广告体验:去除官方客户端的广告干扰…...
SEO优化文章标题需要注意的重点有什么
SEO优化文章标题需要注意的重点有什么 在当前数字营销的环境中,SEO优化文章标题是吸引目标用户点击的重要因素之一。拥有一个高效的标题不仅可以提升文章的曝光率,还能提高用户的参与度和转化率。SEO优化文章标题需要注意的重点有哪些呢?本文…...
《QGIS快速入门与应用基础》253:元素锁定(防止误操作)
作者:翰墨之道,毕业于国际知名大学空间信息与计算机专业,获硕士学位,现任国内时空智能领域资深专家、CSDN知名技术博主。多年来深耕地理信息与时空智能核心技术研发,精通 QGIS、GrassGIS、OSG、OsgEarth、UE、Cesium、OpenLayers、Leaflet、MapBox 等主流工具与框架,兼具…...
【毕业设计】微信小程序文创商城-从真实支付到模拟支付的实现与优化
1. 微信小程序文创商城支付功能概述 做毕业设计选择微信小程序文创商城是个不错的选题,尤其是支付功能的实现,既能锻炼技术能力,又很实用。我去年指导过几个类似的项目,发现学生们最头疼的就是支付模块。真实支付需要营业执照和公…...
面试官最爱问的Java集合+多线程,详解+示例
文章目录一、开篇:为什么面试官揪着这俩不放?二、Java集合:别只会用ArrayList了2.1 List三兄弟:ArrayList、LinkedList、Vector2.2 Set家族:HashSet、LinkedHashSet、TreeSet2.3 Map三巨头:HashMap、Concur…...
2026年上海网站GEO优化方法大揭秘,让你的网站脱颖而出!
在数字化浪潮席卷的当下,拥有一个出色的网站是企业立足市场的关键。而在上海这个充满机遇与挑战的商业之都,网站的GEO优化更是成为了众多企业提升竞争力的重要手段。那么,在2026年,究竟有哪些有效的GEO优化方法能让你的网站脱颖而…...
Phi-4-mini-reasoning开源模型教育价值:高校AI课程实验设计与评估标准
Phi-4-mini-reasoning开源模型教育价值:高校AI课程实验设计与评估标准 1. 引言:AI教育的新工具 在人工智能教育领域,如何让学生既能理解前沿技术原理,又能获得实际动手能力,一直是教学设计的难点。Phi-4-mini-reason…...
Qwen3.5-9B-AWQ-4bit惊艳效果展示:高清图识+中文摘要真实生成作品集
Qwen3.5-9B-AWQ-4bit惊艳效果展示:高清图识中文摘要真实生成作品集 1. 模型能力概览 Qwen3.5-9B-AWQ-4bit是一款让人眼前一亮的视觉理解模型,它能像人类一样"看懂"图片内容,并用流畅的中文给出专业分析。这个模型特别擅长处理各种…...
Leather Dress Collection实战案例:用Leather TankTop Pants生成运动风皮革穿搭图集
Leather Dress Collection实战案例:用Leather TankTop Pants生成运动风皮革穿搭图集 1. 引言:当皮革遇上运动风 想象一下,你正在为一个运动潮牌设计新一季的视觉素材。客户想要一种既酷炫又充满活力的感觉——皮革的质感,运动的…...
