首页 > 其他分享 >Android官方架构组件ViewModel_从前世今生到追本溯源,android插件化开发指南

Android官方架构组件ViewModel_从前世今生到追本溯源,android插件化开发指南

时间:2024-03-25 20:59:54浏览次数:36  
标签:插件 HolderFragment Fragment ViewModel 追本溯源 class Activity public

ViewModel在对应的 作用域 内保持生命周期内的 局部单例,这就引发一个更好用的特性,那就是FragmentActivity等UI组件间的通信。

3.3 更方便UI组件之间的通信

一个Activity中的多个Fragment相互通讯是很常见的,如果ViewModel的实例化作用域为Activity的生命周期,则两个Fragment可以持有同一个ViewModel的实例,这也就意味着数据状态的共享:

public class AFragment extends Fragment {
private CommonViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(CommonViewModel.class);
}
}

public class BFragment extends Fragment {
private CommonViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(CommonViewModel.class);
}
}

上面两个Fragment getActivity()返回的是同一个宿主Activity,因此两个Fragment之间返回的是同一个ViewModel

我不知道正在阅读本文的您,有没有冒出这样一个想法:

ViewModel提供的这些特性,为什么感觉互相之间没有联系呢?

这就引发下面这个问题,那就是:

这些特性的本质是什么?

4. ViewModel:对状态的持有和维护

ViewModel层的根本职责,就是负责维护UI的状态,追根究底就是维护对应的数据——毕竟,无论是MVP还是MVVM,UI的展示就是对数据的渲染。

  • 1.定义了ViewModel的基类,并建议通过持有LiveData维护保存数据的状态;
  • 2.ViewModel不会随着Activity的屏幕旋转而销毁,减少了维护状态的代码成本(数据的存储和读取、序列化和反序列化);
  • 3.在对应的作用域内,保正只生产出对应的唯一实例,多个Fragment维护相同的数据状态,极大减少了UI组件之间的数据传递的代码成本。

现在我们对于ViewModel的职责和思想都有了一定的了解,按理说接下来我们应该阐述如何使用ViewModel了,但我想先等等,因为我觉得相比API的使用,掌握其本质的思想会让你在接下来的代码实践中如鱼得水

不,不是源码解析…

通过库提供的API接口作为开始,阅读其内部的源码,这是标准掌握代码内部原理的思路,这种方式的时间成本极高,即使有相关源码分析的博客进行引导,文章中大片大片的源码和注释也足以让人望而却步,于是我理所当然这么想

先学会怎么用,再抽空系统学习它的原理和思想吧…

发现没有,这和上学时候的学习方式竟然截然相反,甚至说本末倒置也不奇怪——任何一个物理或者数学公式,在使用它做题之前,对它背后的基础理论都应该是优先去系统性学习掌握的(比如,数学公式的学习一般都需要先通过一定方式推导和证明),这样我才能拿着这个知识点对课后的习题举一反三。这就好比,如果一个老师直接告诉你一个公式,然后啥都不说让你做题,这个老师一定是不合格的。

我也不是很喜欢大篇幅地复制源码,我准备换个角度,站在Google工程师的角度看看怎么样设计出一个ViewModel

站在更高的视角,设计ViewModel

现在我们是Google工程师,让我们再回顾一下ViewModel应起到的作用:

  • 1.规范化了ViewModel的基类;
  • 2.ViewModel不会随着Activity的屏幕旋转而销毁;
  • 3.在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信。

1.设计基类

这个简直太简单了:

public abstract class ViewModel {

protected void onCleared() {
}
}

我们定义一个抽象的ViewModel基类,并定义一个onCleared()方法以便于释放对应的资源,接下来,开发者只需要让他的XXXViewModel继承这个抽象的ViewModel基类即可。

2.保证数据不随屏幕旋转而销毁

这是一个很神奇的功能,但它的实现方式却非常简单,我们先了解这样一个知识点:

setRetainInstance(boolean)Fragment中的一个方法。将这个方法设置为true就可以使当前FragmentActivity重建时存活下来

这似乎和我们的功能非常吻合,于是我们不禁这样想,可不可以让Activity持有这样一个不可见的Fragment(我们干脆叫他HolderFragment),并让这个HolderFragment调用setRetainInstance(boolean)方法并持有ViewModel——这样当Activity因为屏幕的旋转销毁并重建时,该Fragment存储的ViewModel自然不会被随之销毁回收了:

public class HolderFragment extends Fragment {

public HolderFragment() { setRetainInstance(true); }

private ViewModel mViewModel;
// getter、setter…
}

当然,考虑到一个复杂的UI组件可能会持有多个ViewModel,我们更应该让这个不可见的HolderFragment持有一个ViewModel的数组(或者Map)——我们干脆封装一个叫ViewModelStore的容器对象,用来承载和代理所有ViewModel的管理:

public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
// put(), get(), clear()…
}

public class HolderFragment extends Fragment {

public HolderFragment() { setRetainInstance(true); }

private ViewModelStore mViewModelStore = new ViewModelStore();
}

好了,接下来需要做的就是,在实例化ViewModel的时候:

1.当前Activity如果没有持有HolderFragment,就实例化并持有一个HolderFragment 2.Activity获取到HolderFragment,并让HolderFragmentViewModel存进HashMap中。

这样,具有生命周期的Activity在旋转屏幕销毁重建时,因为不可见的HolderFragment中的ViewModelStore容器持有了ViewModelViewModel和其内部的状态并没有被回收销毁。

这需要一个条件,在实例化ViewModel的时候,我们似乎还需要一个Activity的引用,这样才能保证 获取或者实例化内部的HolderFragment并将ViewModel进行存储

于是我们设计了这样一个的API,在ViewModel的实例化时,加入所需的Activity依赖:

CommonViewModel viewModel = ViewModelProviders.of(activity).get(CommonViewModel.class)

我们注入了Activity,因此HolderFragment的实例化就交给内部的代码执行:

HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = createHolderFragment(fm);
return holder;
}

这之后,因为我们传入了一个ViewModelClass对象,我们默认就可以通过反射的方式实例化对应的ViewModel,并交给HolderFragment中的ViewModelStore容器存起来:

public T get(Class modelClass) {
// 通过反射的方式实例化ViewModel,并存储进ViewModelStore
viewModel = modelClass.getConstructor(Application.class).newInstance(mApplication);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}

3.在对应的作用域内,保正只生产出对应的唯一实例

如何保证在不同的Fragment中,通过以下代码生成同一个ViewModel的实例呢?

public class AFragment extends Fragment {
private CommonViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(CommonViewModel.class);
}
}

public class BFragment extends Fragment {
private CommonViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(CommonViewModel.class);
}
}

其实很简单,只需要在上一步实例化ViewModelget()方法中加一个判断就行了:

public T get(Class modelClass) {
// 先从ViewModelStore容器中去找是否存在ViewModel的实例

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

Android学习PDF+学习视频+面试文档+知识点笔记

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

PDF+学习视频+面试文档+知识点笔记](https://bbs.csdn.net/topics/618156601)

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-ssFSPRE5-1711350702468)]

【Android高级架构视频学习资源】

**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

标签:插件,HolderFragment,Fragment,ViewModel,追本溯源,class,Activity,public
From: https://blog.csdn.net/2301_79058150/article/details/137015088

相关文章

  • 适应多样化需求:WASM 插件在全链路灰度发布中的应用
    作者:十眠据调研数据显示,约70%的生产故障是由变更引起的。为了消除变更过程存在的风险,在发布过程中,我们总是希望能够用小部分特定流量来验证下新发布应用是否正常。即使新版本有问题,也能及时发现,控制影响面,保障了整体的稳定性,这就是微服务架构下的全链路灰度的能力。MSE在微服......
  • SD相见恨晚的提示词插件,简直堪称神器!
    你写提示词的时候还在用翻译词典一个个查吗?你分隔提示词的时候还在手打逗号吗?你调提示词顺序的时候还在一个词一个词移动吗?小编发现了一个提示词插件很不错,还带英语翻译的。原来一直知道有提示词插件,但一直没有配置,今天试了一下,真香了。这篇文章,看看谁还是用词典查英文......
  • 这个SD插件处理服装太给力了!
    今天我为大家详细介绍了StableDiffusion中一个非常有用的插件,名为ADetailer。......
  • 一款完全免费无广告的浏览器插件
    界面上的图标都支持拖拽移动位置一、官网官方网站www.brtab.top二、功能精美的小组件天气组件:可以查看不同城市的当前以及未来7天的天气变化,并了解当前的所有天气指数日历组件:可以显示当前的日期,包含农历日期,在详情中可以查看每日的忌宜以及节日等恋爱纪......
  • 解放双手!这个插件只要一张表就能生成CRUD代码
    大家好,我是Java陈序员。问君能有几多愁,代码一行又一行!作为码农,代码是写不完的,而偷懒又是人的天性,能少干一点就少干一点。今天,给大家介绍一个IDEA插件,帮助你快速生成出CRUD的代码!关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等......
  • 【ComfyUI插件】Comfyroll节点 (二)
    前言:通过本教程的学习,我们将逐一探索每个节点的独特功能和应用场景,并掌握如何将它们应用于实际项目中。你将能够:批量处理图像,节省时间和精力;巧妙地合并和交错列表数据,创造新的序列;重复执行操作,以实现特定的数据处理模式;执行数学运算,特别是针对列表数据的乘积操作;将文本列表转......
  • Vim - vimrc常用配置和插件的使用
    基础常用命令I#跳转到行首并进入编辑A#跳转到行尾并进入编辑j#跳转到下一行.#重复上一次的修改(比如给每一行最后加上";",可以按A将光标移动到行尾,输入;,然后按j跳转到下一行,在按.)C#删除当前光标位置到当前行最后的文本,并进入编辑模式s#删除光标后的一个字......
  • verilog注释及vscode插件terosHDL
    模型功能实现代码的注释的方法基于vscode的文档自动生成模型框图`timescale1ns/1ps/**///*******************************************************************************//Company:FpgaPublish//Engineer:FP////CreateDate:2024/03/2412:39:43......
  • Kettle之Neo4j插件
    Neo4j插件下载安装下载地址:https://github.com/knowbi/knowbi-pentaho-pdi-neo4j-output/releases解压文件,放入kettle的plugins目录中需要先删除所有历史/plugins/Neo4JOutput的文件夹重启kettle使用kettle版本插件,已不再维护;现维护的为kettle分支hop,地址:https://github.c......
  • 【ComfyUI插件】Comfyroll节点 (一)
    知识星球:71297236该星球不仅包含大量的节点详细介绍还定期做工作流分享以及思路详解,还会解决各种报错问题,欢迎大家加入!前言:ComfyrollStudio是一个强大的自定义节点集合,旨在为ComfyUI用户提供更丰富、更专业的图像生成和编辑工具。通过这些节点,你将可以探索新的创作可能......