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原理学习总结 的相关文章

随机推荐

  • 【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