从LeakCanary看ViewModel生命周期监控

前面两篇文章中已经了解了LeakCanary中Service和Fragment生命周期监控的实现,那么ViewModel生命周期监控又是怎么实现的呢?

同样的,要了解ViewModel生命周期监控,我们首先应该清楚在代码结构中ViewModel是如何存储获取的,什么时候会销毁ViewModel对象,这也是面试中比较常见的问题。

ViewModel的分类

在Android官方文档中搜索ViewModel,可以看到下图:

24-5-1

Google官方先是推出android.arch.lifecycle:viewmodel,随后正式引入AndroidX版本,由于android.arch.lifecycle实现比较久远,这里我们重点讨论androidx中的ViewModel生命周期监控。

ViewModel原理简介

在ViewModel机制中,主要包含ViewModelStore,ViewModelStoreOwner和ViewModelProvider这两个角色,其中ViewModelStoreOwner接口由持有ViewModelStore的类实现,ViewModelStore主要用于存储ViewModel对象,ViewModelProvider是一个工具类,用于构造ViewModel对象,同时在构造时会将构造的对象添加到ViewModelStore中。

ViewModel中的类持有关系

viewMode class

如上图所示,开发者通过ViewModelProvider获取ViewModel实例对象,该对象通过Factory构造,构造完成后添加到ViewModelStore中,ViewModelStore被ViewModelStoreOwner持有。

AndroidX中的ViewModel实现

ViewModel in AndroidX.drawio

如上图所示,为androidx中ViewModel相关的实现,图示比较清楚,配合代码观看即可,不做赘述。

ViewModel的销毁

前面看到ViewModel是存储在ViewModelStore中,那么其销毁自然是在ViewModelStore中处理,ViewModelStore代码如下:

image-20230812222904696

可以看到clear方法就是用来清理ViewModelStore中存储的ViewModel对象的,在Activity onDestroy是会调用ViewModelStore的clear方法。

ViewModel销毁监控

从ViewModelStore clear方法的实现可以看出,其首先会遍历mMap中的ViewModel对象,调用每一个的clear方法,随后清空整个mMap,这也就意味着,我们可以通过向该ViewModelStore添加一个ViewModel来达到监控ViewModel销毁的目的,当ViewModel需要被销毁时,我们添加的ViewModel对象的clear方法会被调用,此时mMap还没有清空,我们可以通过遍历mMap来得到所有应该被清空的ViewModel对象信息。

向ViewModelStore添加ViewModel对象

向ViewModelStore添加我们自定义的ViewModelClearedWatcher,用于监控ViewModel的销毁,实现代码如下:

public class ViewModelWatcher {private static final String TAG = "ViewModelWatcher";private static volatile ViewModelWatcher mInstance;private ViewModelWatcher() {}public static ViewModelWatcher getInstance() {if (null == mInstance) {synchronized (ViewModelWatcher.class) {if (null == mInstance) {mInstance = new ViewModelWatcher();}}}return mInstance;}public void init(Application application) {application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {@Overridepublic void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {// 如果Activity是androidx中的ComponentActivity,// 则向该Activity中添加ViewModelif (activity instanceof ComponentActivity) {ViewModelProvider viewModelProvider = new ViewModelProvider((ViewModelStoreOwner) activity, new ViewModelProvider.Factory() {@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (modelClass.isAssignableFrom(ViewModelClearedWatcher.class)) {return (T) (new ViewModelClearedWatcher((ViewModelStoreOwner) activity));}return null;}});viewModelProvider.get(ViewModelClearedWatcher.class);}}@Overridepublic void onActivityStarted(@NonNull Activity activity) {}@Overridepublic void onActivityResumed(@NonNull Activity activity) {}@Overridepublic void onActivityPaused(@NonNull Activity activity) {}@Overridepublic void onActivityStopped(@NonNull Activity activity) {}@Overridepublic void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}@Overridepublic void onActivityDestroyed(@NonNull Activity activity) {}});}class ViewModelClearedWatcher extends ViewModel {private ViewModelStoreOwner mViewModelStoreOwner;public ViewModelClearedWatcher(ViewModelStoreOwner viewModelStoreOwner) {this.mViewModelStoreOwner = viewModelStoreOwner;}@Overrideprotected void onCleared() {Log.d(TAG,"view model has been cleared!");super.onCleared();}}
}

运行可以看到确实监听到clear方法了,日志如下:

image-20230813000016582

获取所有即将销毁的ViewModel信息

前面已了解过ViewModel存储在ViewModelStore的mMap对象中,这也就意味着我们可以通过反射获取Map对象并遍历来获取即将被销毁的所有ViewModel信息,代码如下:

class ViewModelClearedWatcher extends ViewModel {private ViewModelStoreOwner mViewModelStoreOwner;public ViewModelClearedWatcher(ViewModelStoreOwner viewModelStoreOwner) {this.mViewModelStoreOwner = viewModelStoreOwner;}@Overrideprotected void onCleared() {Log.d(TAG, "view model has been cleared!");Map<String, ViewModel> map = getMapFromViewModelStore();if (map != null && !map.isEmpty()) {for (ViewModel viewModel : map.values()) {Log.d(TAG, "viewModel been cleared:" + viewModel.toString());}}super.onCleared();}private Map<String, ViewModel> getMapFromViewModelStore() {try {Class<?> viewModelStoreClass =Class.forName(ViewModelStore.class.getName());Field field = viewModelStoreClass.getDeclaredField("mMap");field.setAccessible(true);return (Map<String, ViewModel>) field.get(mViewModelStoreOwner.getViewModelStore());} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) {e.printStackTrace();return null;}}
}

运行结果如下:

image-20230813001757434

至此我们就完成了androidx包中Activity关联的ViewModel销毁的监听,至于androidx包下Fragment关联的ViewModel的监听以及arch包下ViewModel的监听,思路是一样的,大家可以探索尝试下,在此不做赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/95780.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Python 在 NLP 中进行文本预处理

一、说明 自然语言处理 &#xff08;NLP&#xff09; 是人工智能 &#xff08;AI&#xff09; 和计算语言学的一个子领域&#xff0c;专注于使计算机能够理解、解释和生成人类语言。它涉及计算机和自然语言之间的交互&#xff0c;允许机器以对人类有意义和有用的方式处理、分析…

SpringBoot代理访问本地静态资源400 404

SpringBoot代理访问静态资源400 404 背景&#xff1a;pdf文件上传到linux服务器上&#xff0c;使用SpringBoot代理访问问题&#xff1a;访问过程中可能会出现400、404问题 前提&#xff1a;保证有文件&#xff0c;并且文件路径正确 SpringBoot如何配置静态资源代理&#xff0…

[python] Kmeans文本聚类算法+PAC降维+Matplotlib显示聚类图像

0 前言 本文主要讲述以下几点&#xff1a; 1.通过scikit-learn计算文本内容的tfidf并构造N*M矩阵(N个文档 M个特征词)&#xff1b; 2.调用scikit-learn中的K-means进行文本聚类&#xff1b; 3.使用PAC进行降维处理&#xff0c;每行文本表示成两维数据&…

8 种主流数据迁移工具技术选型

前言 最近有些小伙伴问我&#xff0c;ETL数据迁移工具该用哪些。 ETL(是Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程)&#xff0c;对于企业应用来说&#xff0c;我们经常会遇到各种数据的处理、转换、迁移的场景。 今天特地给大家汇总了一些目前…

pdf怎么合并在一起?这几个合并方法了解一下

pdf怎么合并在一起&#xff1f;在日常工作、学习和生活中&#xff0c;我们常常会遇到需要将多个PDF文件合并成一个文件的情况。比如&#xff0c;在学术论文写作中&#xff0c;我们可能需要将多篇论文合并成一个文件进行打印和提交。在工作中&#xff0c;我们可能需要将多个报告…

STM32——SPI外设总线

SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先行 时钟频率&#xff1a; fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 支持多主机模型、主或从操作 可…

耕地单目标语义分割实践——Pytorch网络过程实现理解

一、卷积操作 &#xff08;一&#xff09;普通卷积&#xff08;Convolution&#xff09; &#xff08;二&#xff09;空洞卷积&#xff08;Atrous Convolution&#xff09; 根据空洞卷积的定义&#xff0c;显然可以意识到空洞卷积可以提取到同一输入的不同尺度下的特征图&…

excel常见的数学函数篇2

一、数学函数 1、ABS(number)&#xff1a;返回数字的绝对值 语法&#xff1a;ABS(数字)&#xff1b;返回数字的绝对值&#xff1b;若引用单元格&#xff0c;把数字换为单元格地址即可 2、INT(number)&#xff1a;向小取整 语法&#xff1a;INT(数字)&#xff1b;若引用单元格…

Element Plus el-table 数据为空时自定义内容【默认为 No Data】

1. 通过 Table 属性设置 <div class"el-plus-table"><el-table empty-text"暂无数据" :data"tableData" style"width: 100%"><el-table-column prop"date" label"Date" width"180" /&g…

Python Opencv实践 - 图像仿射变换

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR) rows,cols img.shape[:2] print(img.shape[:2])#使用getAffineTransform来获得仿射变换的矩阵M #cv.getAffineTransform(…

Bingchat和ChatGPT主要区别

Bing Chat由chatgpt GPT-4技术提供支持&#xff0c;这是流行的ChatGPT的最新语言模型。Bing Chat通过更具交互性和上下文联动的响应来优化搜索引擎。它允许用户提出问题并获得更人性化、精确化或创造力的答案。用户还可以在答案末尾查看的参考来源。该工具可以充当个人研究、计…

大数据平台是什么意思?有什么用?一般包含哪些模块?

大数据时代&#xff0c;还有很多人不知道大数据平台是什么意思&#xff1f;有什么用&#xff1f;一般包含哪些模块&#xff1f;今天我们就一起来简单了解一下吧&#xff01;仅供参考哦&#xff01; 大数据平台是什么意思&#xff1f;有什么用&#xff1f;一般包含哪些模块&am…

Lnton羚通关于Optimization在【PyTorch】中的基础知识

OPTIMIZING MODEL PARAMETERS &#xff08;模型参数优化&#xff09; 现在我们有了模型和数据&#xff0c;是时候通过优化数据上的参数来训练了&#xff0c;验证和测试我们的模型。训练一个模型是一个迭代的过程&#xff0c;在每次迭代中&#xff0c;模型会对输出进行猜测&…

工程项目管理系统源码+功能清单+项目模块+spring cloud +spring boot em

​ 工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

衣服材质等整理(时常更新)

参考文章&图片来源 https://zhuanlan.zhihu.com/p/390341736 00. 天然纤维 01. 化学纤维 02. 聚酯纤维&#xff08;即&#xff0c;涤纶&#xff09; 一种由有机二元酸和二元醇通过化学缩聚制成的合成纤维。具有出色的抗皱性和保形性&#xff0c;所制衣物在穿着过程中不容…

解决git reset --soft HEAD^撤销commit时报错

今天在使用git回退功能的时候&#xff0c;遇到以下错误&#xff1a; 解决git reset --soft HEAD^撤销commit时报错 问题&#xff1a; 在进行完commit后&#xff0c;想要撤销该commit&#xff0c;于是使用了git reset --soft HEAD^命令&#xff0c;但是出现如下报错&#xff1…

android 12系统加上TTS引擎

系统层修改&#xff1a; 1.frameworks/base/packages/SettingsProvider/res/values/defaults.xml <string name"def_tts"></string> 2.frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java loadString…

206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&a…

学习左耳听风栏目90天——第七天 7/90(学习左耳朵耗子的工匠精神,对技术的热爱)【每个程序员都该知道的事】

每个程序员都该知道的事 每个程序员都应该要读的书每个搞计算机专业的学生应有的知识LinkedIn 高效的代码复查技巧编程语言和代码质量的研究报告 每个程序员都应该要读的书 每个搞计算机专业的学生应有的知识 LinkedIn 高效的代码复查技巧 编程语言和代码质量的研究报告