Android架构——ViewModel原理学习总结

2023-11-10

本文是楼主学习ViewModel 源码的一些总结,感觉ViewModel的源码是Android 三大架构中 最容易理解的一个了。本文ViewModel基于版本androidx.lifecycle:lifecycle-viewmodel:2.2.0

本文内容结构

一、简单介绍下ViewModel有什么作用和优点

二、类图总结ViewModel原理

有错漏之处 请多多指教。

ViewModel作用

通常与LiveData一起使用,

(1)将activity, fragment里关于数据操作的逻辑抽离出来,封装到ViewModel中,所以ViewMoel 持有一个成员变量LiveData<T>。

(2)数据的操作包括什么呢? a. 从DB和缓存读取数据,显示到UI;  b. 通过网络到后台拉取数据,持久化到本地,更新DB和缓存,通知UI刷新。

(3)因此ViewModel 应该持有一个 成员变量Repository(相当于一个管理类, 命名可以命名为其他如XXXManager),做(2)的事情。 而组件activity, fragment应该持有一个成员变量ViewModel , 如图所示

图片来源LiveData + ViewModel + Room (Google 官文)+Demo - 简书   

demo地址:MVVM: ViewModel+LiveData+DataBinding+Retrofit+Room+Paging+RxJava 总结与实践(Java实现)_xiaobaaidaba123的专栏-CSDN博客

ViewModel优点

1. 当横竖屏发生切换时,activity会重建,但是ViewModel不需要重建。

2. ViewModel可以避免内存泄漏问题,Activity destroy时会调用ViewModel的onCleared()方法。

3. 可以解决同一个Activity的不同Fragment的数据共享问题。

ViewModel 原理学习总结

 【架构类图】一个图总结

【ViewModelProvider】一两句话总结

1) ViewModelProvider持有两个成员变量 ViewModerStore ——存储ViewModel  和 Factory —— 创建ViewModel。

因此了解ViewModelProvider 的职责——可以把它看成一个wrapper——打包了创建ViewModel和存储ViewModel的功能。

public class ViewModelProvider {

    private static final String DEFAULT_KEY =
            "android.arch.lifecycle.ViewModelProvider.DefaultKey";

    /**
     **************************************************
     *  ViewModelProvider持有的两个成员变量
     **************************************************
     */
    private final Factory mFactory;
    private final ViewModelStore mViewModelStore;


    /**
     **************************************************
     * 实现Factory接口来创建ViewModel
     **************************************************
     */
    public interface Factory {
        <T extends ViewModel> T create(Class<T> modelClass);
    }


    /**
     **************************************************
     *  ViewModelProvider构建方法
     *  参数 ViewModelStoreOwner 和 Factory
     *  ViewModelStoreOwner  是一个接口,可以返回ViewModelStore
     **************************************************
     */
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

    /**
     **************************************************
     *  ViewModelProvider构建方法
     *  参数 ViewModelStore 和 Factory
     **************************************************
     */
    public ViewModelProvider(ViewModelStore store, Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }

    /**
     **************************************************
     * 先获取modelclass名字,再调用get (key, modelclass) 获取ViewModel
     **************************************************
     */
    public <T extends ViewModel> T get(Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

    /**
     **************************************************
     * 通过key值从ViewModelStore 中获取ViewModel, 如果没有,则通过factory构建一个,再存储到
     * ViewModelStore
     **************************************************
     */
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }

        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

    /**
     **************************************************
     *  该工厂类  通过java反射构建ViewModel 调用无参构造方法
      **************************************************
     */
    public static class NewInstanceFactory implements Factory {

        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            //noinspection TryWithIdenticalCatches
            try {
                return modelClass.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
    }
}

【ViewModelStore】一两句话总结

1)ViewModelStore作用很简单——内部持有一个HashMap,存储ViewModel

public class ViewModelStore {

    /**
     **************************************************
     *  hash map存储viewModel
     **************************************************
     */
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

     /**
     **************************************************
     *  put方法
     **************************************************
     */

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.get(key);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
        mMap.put(key, viewModel);
    }

     /**
     **************************************************
     *  get方法 
     **************************************************
     */

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    /**
     **************************************************
     *  清除hashMap
     **************************************************
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

横竖屏切换,为什么ViewModel不会重建

 1)Activity销毁前,先把ViewModelStore保存起来

    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

 2)Activity 重建后调用getViewModelStore()

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android架构——ViewModel原理学习总结 的相关文章

  • PhoneGap/Cordova 应用程序通知

    我是 PhoneGap Cordova 的新手 我希望向我的应用程序添加一些通知 推送通知 因此当应用程序上发布新文章时 它会提醒用户 本地通知 在设定的时间间隔 日期和时间 我可以提示用户我的应用程序上的最新文章 我进行了大量搜索 但找不
  • 使用 JSONArray 还是普通数组来存储/读取数据更有效?

    我正在使用一个连接到PHP MySQL返回所有内容的服务器JSON格式 例如 用户列表作为JSONArray of JSONObject 每个对象都包含单个用户的信息 姓名 位置 电话号码等 处理这种格式的信息时 将所有内容保留在其中会更有
  • 如何通过我的活动在 Android 中设置铃声?

    我正在尝试找到一种方法来通过 Android 活动中的代码设置新的默认铃声 我已经将铃声下载到bytearray 最后 我设法将默认铃声设置为我下载的铃声 下面不包含下载代码 仅包含将其设置为默认铃声所需的代码 File k new Fil
  • 如果使用grifika的ContinualCaptureActivity中的预览方式,相机预览的视野会更小

    我们知道 当相机预览比例设置为时 在相同距离下我们会得到更大的预览视野4 3代替16 9 具体如下 Android Camera API 奇怪的缩放效果 https stackoverflow com questions 20664628
  • ADB TCPIP 连接问题

    我有两台 Galaxy S3 其中一个已扎根 另一个则未扎根 因此 当我尝试通过本地网络连接它们时 计算机可以看到已root的计算机 但是正常的就卡在tcpip这一步了 所以 我写 adb tcpip 5555 It says restar
  • 需要 Android webview window.open() 和 window.close() 的信息

    我正在开发一个安卓应用程序 这是我网站的 WebView 该网站包含一个弹出按钮 单击该按钮后 将打开一个新窗口并显示内容 该链接可以来自外部站点 然而 当我实现此操作时 新选项卡正在打开 之后它会弹出以打开浏览器 尽管在 Web 视图中打
  • 错误类型 3 - 活动类不存在

    我正在尝试运行 webRTC 应用程序 但返回以下错误 启动应用程序 com onlinevoicecallapp com onlinevoicecallapp MainActivity 设备外壳命令 am start n com onli
  • HMS 核心地图套件在我的 Android 应用程序上根本无法工作

    我正在尝试在我的应用程序中使用华为 HMS 地图套件 我对整体地图很陌生 无论是来自谷歌还是华为 我按照文档中的教程以及华为提供的代码实验室中的说明进行操作 并将我的代码在一起 但是当我运行地图活动时 什么也没有出现 我得到的只是一个空白活
  • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

    这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
  • 选项卡主机内的 Android Fragment 视图状态 [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Fragment 为 Android 中的每个选项卡单独的返回堆栈 https stackoverflow com questions 6987334 separate back stack f
  • Android 上的 MIDI:Java 和/或 AIR 库

    一段时间以来 我一直在考虑在 iPad 上 重新 构建一个应用程序 其中我将使用 Objective C 和DSMI http dsmi tobw net 将 MIDI 信号发送到主机 这还不错 我的意思是 除了实际编写应用程序之外 现在我
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 移动设备上的 TensorFlow(Android、iOS、Windows Phone)

    我目前正在寻找不同的深度学习框架 特别是用于训练和部署卷积神经网络 要求是 它可以在带有 GPU 的普通 PC 上进行训练 但训练后的模型必须部署在三个主要的移动操作系统上 即 Android iOS 和 Windows Phone Ten
  • 无法使用 findViewById() 找到视图

    我找不到TextView通过致电findViewById 即使 ID 确实存在 OtherActivity public class OtherActivity extends Activity Override protected voi
  • 哪个视图最亮?

    在Android中 哪个是轻量级视图 例如 View Textview Edittext 等 在某些情况下 我们需要使用视图来填充区域而不向用户显示视图 同时屏幕加载速度应该很快 您可以使用空间 android widget Space S
  • 当目标小于 Android O 时,如何在 Android O 上创建快捷方式?

    背景 Android O 对快捷方式的工作方式进行了各种更改 https developer android com preview behavior changes html as https developer android com
  • 如何在android中通过蓝牙向配对设备发送短信?

    在我的应用程序中 我想通过蓝牙发送和接收短信 我可以在列表视图中看到配对设备名称和地址的列表 但是当我尝试向配对设备发送文本时 什么也没有发生 在其他设备中没有收到文本 这是我向配对设备发送消息的代码 private void sendDa
  • 检查应用程序是否在 Android Market 上可用

    给定 Android 应用程序 ID 包名称 如何以编程方式检查该应用程序是否在 Android Market 上可用 例如 com rovio angrybirds 可用 而 com random app ibuilt 不可用 我计划从
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向
  • LifeCycleAware Fragment 中的片段生命周期事件

    我有一个生命周期感知片段和一个LifecycleObserver class public class MyFragment extends Fragment Override public void onCreate Nullable B

随机推荐

  • 【c4d】将3DMAX的模型(.max)导入c4d

    C4D安装完毕后 直接将 max文件拖入C4D会提示 Unknow file format 未知的文件格式 如下图 将 max文件导入c4d 需要一个插件 maxToC4d 需要注意的是 这个插件的版本和C4D的版本是对应的 maxToC4
  • ZooKeeper 未授权访问漏洞利用

    点击 仙网攻城狮 关注我们哦 不当想研发的渗透人不是好运维 让我们每天进步一点点 简介 ZooKeeper是一个分布式的 开放源码的分布式应用程序协调服务 它是一个为分布式应用提供一致性服务的软件 提供的功能包括 配置维护 域名服务 分布式
  • windows10自带屏保设置

    windows10系列文章目录 文章目录 windows10系列文章目录 前言 一 操作步骤 1 打开个性化设置 2 锁屏界面 3 设置等待时间 360健康助手 1 添加健康助手 前言 windows10自带屏保默认设置是 5分钟没有人为对
  • MyBatis框架详解

    MyBatis属于orm框架 MyBatis 是支持定制化 SQL 存储过程以及高级映射的优秀的持久层框架 其主要就完成2件事情 封装JDBC操作 利用反射打通Java类与SQL语句之间的相互转换 MyBatis使用简单的XML或注解用于配
  • 初步了解python与爬虫

    初步了解 python与爬虫 1 什么是python 答 python是一种动态的 面向对象的计算机程序语言 像C java C 一样 它的特点就是语法简洁 具有丰富的 功能强大的第三方库函数 2 什么是爬虫 答 爬虫即Web Spider
  • 移动通信原理B-------例题解答2

    移动通信原理B例题解答2 移动通信原理B 例题解答2 一 题目 若一发射机发射载频为1850Mhz 一辆汽车以每小时72Km h的速度运动 计算在以下情况下接收机的载波频率 1 汽车沿直线朝向发射机运动 2 汽车沿直线背向发射机运动 3 汽
  • linux服务器基础知识,linux基础知识1

    1 在chmod 命令中 v参数的作用是 A 详细说明组的变化 B 详细说明权限的变化 C 改变本目录及其所有子目录的文件的权限 D 在文件的权限确实改变时进行详细的说明 2 为了显示文件 test 的内容可以用命令 A cat test
  • jQuery 事件 - trigger() 方法

    实例
  • SCADA和三大工业控制系统PLC、DCS、FCS

    一 引言 工业控制系统 ICS 是一个通用术语 随着工业技术的快速发展 相继出现了集散控制系统和现场控制系统 涵盖多种类型的控制系统 包括监控和数据采集 SCADA 系统 分布式控制系统 DCS 和其他较小的控制系统配置 如经常在工业部门和
  • 剑指Offer-链表-面试题62:圆圈中最后剩下的数字

    面试题62 圆圈中最后剩下的数字 题目描述 每年六一儿童节 牛客都会准备一些小礼物去看望孤儿院的小朋友 今年亦是如此 HF作为牛客的资深元老 自然也准备了一些小游戏 其中 有个游戏是这样的 首先 让小朋友们围成一个大圈 然后 他随机指定一个
  • 基本操作:vscode-git使用和命令

    1 Git简介 GIt git 是一个开源的分布式版本控制系统 可以有效 高速的处理从很小到很大的项目版本管理 通俗的说 解决的问题是 正常开发 一个团队需要很多人来共同开发一个项目 那么就涉及到代码的合并 比如两个人 同时更改了一处代码
  • Python爬取拉勾网职位 - 分析学历与薪资关系及技能词云

    Python拉勾网职位爬取及数据分析可视化 文章目录 Python拉勾网职位爬取及数据分析可视化 1 工具准备 1 安装第三方库 2 安装及配置Chromedriver无头浏览器 3 谷歌浏览器xpath插件安装及配置 4 使用Pychar
  • 焊接机器人的坡口填充功能_《金属焊接》课后习题参考答案完整版

    金属焊接 课后习题 第1章绪论 1 1 什么是焊接 什么叫做焊接技术 储运11 1 01 丛欣欣 答 焊接 是指通过适当的手段 是两个分离的金属物体 同种金属或异种金属 产生原子 分子 间结合而连接一体的连接方法 焊接技术 焊接是一种重要的
  • HTML期末作业-网上书城网上书店

    HTML期末作业 网上书城网上书店 HTML css JavaScript 7个页面 部分源码
  • 史上最强,Jenkins插件实现多个Job并行后再触发Job详细,一篇贯通...

    目录 导读 前言 一 Python编程入门到精通 二 接口自动化项目实战 三 Web自动化项目实战 四 App自动化项目实战 五 一线大厂简历 六 测试开发DevOps体系 七 常用自动化测试工具 八 JMeter性能测试 九 总结 尾部小
  • 【面试】数据仓库面试经验总结

    目录 第一部分 自我介绍 第二部分 专业知识细问 第三部分 数据治理 第四部分 开发 代码能力 第五部分 个人性格测试 第一部分 自我介绍 通常面试官会让进行自我介绍 加项目经历介绍 大多数会按简历上的内容逐条细问 回答的时候尽量根据STA
  • VMWare15.5安装CentOS7.9

    一 创建虚拟机 创建虚拟机 选择自定义 高级 点击下一步 选择默认 点击下一步 选择 稍后安装操作系统 点击下一步 选择要安装的操作系统和版本 点击下一步 修改虚拟机名称和安装路径 点击下一步 根据需要设置处理器数量和内核数量 点击下一步
  • 006.设计原则与思想:规范与重构

    规范与重构 一 理论一 什么情况下要重构 到底重构什么 又该如何重构 1 重构的目的 为什么要重构 why 2 重构的对象 到底重构什么 what 3 重构的时机 什么时候重构 when 4 重构的方法 又该如何重构 how 二 理论二 为
  • elasticsearch-分词测试

    分词结果 tokens token 今天天气 start offset 0 end offset 4 type CN WORD position 0 token 今天 start offset 0 end offset 2 type CN
  • Android架构——ViewModel原理学习总结

    本文是楼主学习ViewModel 源码的一些总结 感觉ViewModel的源码是Android 三大架构中 最容易理解的一个了 本文ViewModel基于版本androidx lifecycle lifecycle viewmodel 2