ViewModel 使用及原理解析

public final MutableLiveData mUserLiveData = new MutableLiveData<>();

public UserModel() {

//模拟从网络加载用户信息

mUserLiveData.postValue(new User(1, “name1”));

}

//模拟 进行一些数据骚操作

public void doSomething() {

User user = mUserLiveData.getValue();

if (user != null) {

user.age = 15;

user.name = “name15”;

mUserLiveData.setValue(user);

}

}

}

  1. 这时候在Activity中就可以使用ViewModel了. 其实就是一句代码简单实例化,然后就可以使用ViewModel了.

//这些东西我是引入的androidx下面的

import androidx.fragment.app.FragmentActivity;

import androidx.lifecycle.Observer;

import androidx.lifecycle.ViewModelProviders;

public class MainActivity extends FragmentActivity {

private TextView mContentTv;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mContentTv = findViewById(R.id.tv_content);

//构建ViewModel实例

final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);

//让TextView观察ViewModel中数据的变化,并实时展示

userModel.mUserLiveData.observe(this, new Observer() {

@Override

public void onChanged(User user) {

mContentTv.setText(user.toString());

}

});

findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

//点击按钮 更新User数据 观察TextView变化

userModel.doSomething();

}

});

}

}

这个时候,我们点击一下按钮(user中的age变为15),我们可以旋转手机屏幕(这个时候其实Activity是重新创建了,也就是onCreate()方法被再次调用,但是ViewModel其实是没有重新创建的,还是之前那个ViewModel),但是当我们旋转之后,发现TextView上显示的age居然还是15,这就是ViewModel的魔性所在.这个就不得不提ViewModel的生命周期了,它只有在Activity销毁之后,它才会自动销毁(所以别让ViewModel持有Activity引用啊,会内存泄露的). 下面引用一下谷歌官方的图片,将ViewModel的生命周期展示的淋漓尽致.

3. ViewModel妙用1: Activity与Fragment"通信"

有了ViewModel,Activity与Fragment可以共享一个ViewModel,因为Fragment是依附在Activity上的,在实例化ViewModel时将该Activity传入ViewModelProviders,它会给你一个该Activity已创建好了的ViewModel,这个Fragment可以方便的访问该ViewModel中的数据.在Activity中修改userModel数据后,该Fragment就能拿到更新后的数据.

public class MyFragment extends Fragment {

public void onStart() {

//这里拿到的ViewModel实例,其实是和Activity中创建的是一个实例

UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);

}

}

4. ViewModel妙用2: Fragment与Fragment"通信"

下面我们来看一个例子(Google官方例子)

public class SharedViewModel extends ViewModel {

private final MutableLiveData selected = new MutableLiveData();

public void select(Item item) {

selected.setValue(item);

}

public LiveData getSelected() {

return selected;

}

}

public class MasterFragment extends Fragment {

private SharedViewModel model;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

itemSelector.setOnClickListener(item -> {

model.select(item);

});

}

}

public class DetailFragment extends Fragment {

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

model.getSelected().observe(this, { item ->

// Update the UI.

});

}

}

  1. 首先定义一个ViewModel,在里面放点数据

  2. 然后在MasterFragment和DetailFragment都可以拿到该ViewModel,拿到了该ViewModel就可以拿到里面的数据了,相当于间接通过ViewModel通信了. so easy…

二、ViewModel源码解析

又到了我们熟悉的源码解析环节

我们从下面这句代码start.

final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);

我们跟着ViewModelProviders.of(this)打开新世界的大门

1. ViewModelProviders.of(this) 方法

/**

  • 用于构建一个ViewModelProvider,当Activity是alive时它会保留所有的该Activity对应的ViewModels.

*/

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity) {

return of(activity, null);

}

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity,

@Nullable Factory factory) {

//检查application是否为空,不为空则接收

Application application = checkApplication(activity);

if (factory == null) {

//构建一个ViewModelProvider.AndroidViewModelFactory

factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);

}

return new ViewModelProvider(activity.getViewModelStore(), factory);

}

ViewModelProviders里面的of()函数其实是为了方便我们构建一个ViewModelProvider.而ViewModelProvider,一看名字就知道干啥的了,就是提供ViewModel的.

Factory是ViewModelProvider的一个内部接口,它的实现类是拿来构建ViewModel实例的.它里面只有一个方法,就是创建一个ViewModel.

/**

  • Implementations of {@code Factory} interface are responsible to instantiate ViewModels.

*/

public interface Factory {

/**

  • Creates a new instance of the given {@code Class}.

  • @param modelClass a {@code Class} whose instance is requested

  • @param The type parameter for the ViewModel.

  • @return a newly created ViewModel

*/

@NonNull

T create(@NonNull Class modelClass);

}

Factory有2个实现类:一个是NewInstanceFactory, 一个是AndroidViewModelFactory .

  • NewInstanceFactory源码

public static class NewInstanceFactory implements Factory {

@SuppressWarnings(“ClassNewInstance”)

@NonNull

@Override

public T create(@NonNull Class 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);

}

}

}

NewInstanceFactory专门用来实例化那种构造方法里面没有参数的class,并且ViewModel里面是不带Context的,然后它是通过newInstance()去实例化的.

  • AndroidViewModelFactory 源码

public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

private static AndroidViewModelFactory sInstance;

/**

  • Retrieve a singleton instance of AndroidViewModelFactory.

  • @param application an application to pass in {@link AndroidViewModel}

  • @return A valid {@link AndroidViewModelFactory}

*/

@NonNull

public static AndroidViewModelFactory getInstance(@NonNull Application application) {

if (sInstance == null) {

sInstance = new AndroidViewModelFactory(application);

}

return sInstance;

}

private Application mApplication;

/**

  • Creates a {@code AndroidViewModelFactory}

  • @param application an application to pass in {@link AndroidViewModel}

*/

public AndroidViewModelFactory(@NonNull Application application) {

mApplication = application;

}

@NonNull

@Override

public T create(@NonNull Class modelClass) {

if (AndroidViewModel.class.isAssignableFrom(modelClass)) {

//noinspection TryWithIdenticalCatches

try {

return modelClass.getConstructor(Application.class).newInstance(mApplication);

} catch (NoSuchMethodException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (IllegalAccessException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (InstantiationException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (InvocationTargetException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

}

}

return super.create(modelClass);

}

}

AndroidViewModelFactory专门用来实例化那种构造方法里面有参数的class,并且ViewModel里面可能是带Context的.

  • 它是通过newInstance(application)去实例化的.如果有带application参数则是这样实例化

  • 如果没有带application参数的话,则还是会走newInstance()方法去构建实例.

AndroidViewModelFactory通过构造方法给ViewModel带入Application,就可以在ViewModel里面拿到Context,因为Application是APP全局的,那么不存在内存泄露的问题.完美解决了有些ViewModel里面需要Context引用,但是又担心内存泄露的问题.

下面我们继续ViewModelProviders.of(this)方法继续分析吧,注意最后一句new ViewModelProvider(activity.getViewModelStore(), factory);第一个参数会调用activity的getViewModelStore()方法(这个方法会返回ViewModelStore,这个类是拿来存储ViewModel的,下面会说到),这里的activity是androidx.fragment.app.FragmentActivity,看一下这个getViewModelStore()方法

/**

  • 获取这个Activity相关联的ViewModelStore

*/

@NonNull

@Override

public ViewModelStore getViewModelStore() {

if (getApplication() == null) {

throw new IllegalStateException("Your activity is not yet attached to the "

  • “Application instance. You can’t request ViewModel before onCreate call.”);

}

if (mViewModelStore == null) {

//获取最近一次横竖屏切换时保存下来的数据

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null) {

// Restore the ViewModelStore from NonConfigurationInstances

mViewModelStore = nc.viewModelStore;

}

if (mViewModelStore == null) {

mViewModelStore = new ViewModelStore();

}

}

return mViewModelStore;

}

//没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore

//注意,这是FragmentActivity中的NonConfigurationInstances(其实Activity中还定义了一个NonConfigurationInstances,内容要比这个多一些,但是由于没有关系到它,这里就不提及了)

static final class NonConfigurationInstances {

Object custom;

ViewModelStore viewModelStore;

FragmentManagerNonConfig fragments;

}

Android横竖屏切换时会触发onSaveInstanceState(),而还原时会调用onRestoreInstanceState(),但是Android的Activity类还有2个方法名为onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()这两个方法。

来具体看看这2个素未谋面的方法

/**

保留所有fragment的状态。你不能自己覆写它!如果要保留自己的状态,请使用onRetainCustomNonConfigurationInstance()

这个方法在FragmentActivity里面

*/

@Override

public final Object onRetainNonConfigurationInstance() {

Object custom = onRetainCustomNonConfigurationInstance();

FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

if (fragments == null && mViewModelStore == null && custom == null) {

return null;

}

NonConfigurationInstances nci = new NonConfigurationInstances();

nci.custom = custom;

nci.viewModelStore = mViewModelStore;

nci.fragments = fragments;

return nci;

}

//这个方法在Activity里面,而mLastNonConfigurationInstances.activity实际就是就是上面方法中年的nci

public Object getLastNonConfigurationInstance() {

return mLastNonConfigurationInstances != null

? mLastNonConfigurationInstances.activity : null;

}

我们来看看getLastNonConfigurationInstance()的调用时机,

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {

mViewModelStore = nc.viewModelStore;

}

}

没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就还在啊,也就避免了横竖屏切换时的数据丢失.

2. viewModelProvider.get(UserModel.class)

下面我们来到那句构建ViewModel代码的后半段,它是ViewModelProvider的get()方法,看看实现,其实很简单

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

【附】相关架构及资料

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

[外链图片转存中…(img-z0s4bjeS-1712301262166)]

[外链图片转存中…(img-UtTGpRsK-1712301262166)]

[外链图片转存中…(img-UasEwq2U-1712301262167)]

[外链图片转存中…(img-ajVaf0Sh-1712301262167)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

【附】相关架构及资料

[外链图片转存中…(img-1vs3RzuX-1712301262167)]

[外链图片转存中…(img-UYJ2Cw0S-1712301262168)]

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RMSNorm】Root Mean Square Layer Normalization

【RMSNorm】Root Mean Square Layer Normalization 论文信息 阅读评价 Abstract Introduction Related Work Background RMSNorm Experiments 论文信息 名称内容论文标题Root Mean Square Layer Normalization论文地址https://arxiv.org/abs/1910.07467发表时间2019-…

linux练习-交互式传参

在shell脚本中&#xff0c;read 向用户显示一行文本并接受用户输入 #!/bin/bash read -p 依次输入你的姓名、年龄、家乡 name age home echo 我是$name,年龄$age,我来自$home

12种常见的软件架构风格

什么是软件架构&#xff1f; 软件架构是定义软件系统的高级结构和组织的过程。它涉及识别和选择正确的组件&#xff0c;决定它们之间如何交互&#xff0c;以及确定它们应该如何组织以实现特定的目标。软件架构的目标是创建一个可维护、可扩展和安全的系统&#xff0c;能够满足…

小红书自动化仿写发文机器人了解一下

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

权限认证SpringCloud GateWay、SpringSecurity、OAuth2.0、JWT一网打尽!

权限认证SpringCloud GateWay、SpringSecurity、OAuth2.0、JWT一网打尽 一、SpringCloud GateWay 1.它是如何工作的&#xff1f; ​ 客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配&#xff0c;它将被发送到Gateway Web处理程序。…

蓝桥杯第十四届--异或和之和

题目描述 给定一个数组 Ai&#xff0c;分别求其每个子段的异或和&#xff0c;并求出它们的和。或者说&#xff0c;对于每组满足 1 ≤ L ≤ R ≤ n 的 L, R &#xff0c;求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L, R 得到的结果加起来的值。 输入格式 输入的第一…

基于ACO蚁群优化的VRPSD问题求解matlab仿真,输出规划路径结果和满载率

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 关键概念与模型 4.2数学模型 5.完整程序 1.程序功能描述 基于ACO蚁群优化的VRPSD问题求解matlab仿真,输出ACO优化的收敛曲线&#xff0c;规划路径结果和每一条路径的满载率。 2.测试软…

C# MES通信从入门到精通(8)——C#调用Webservice服务进行数据交互

前言 在上位机开发领域,使用webservice来访问客户的终端Mes系统是一项必备的技能,本文详细介绍了如何在c#中调用webservice服务,不仅介绍了使用添加服务引用直接调用webservice中的方法外还介绍了使用http的post方法调用webservice方法,过程详细且均为实战经验总结,对于初…

十个排序算法

目录 冒泡排序(Bubble Sort) 选择排序(Select Sort) 插入排序&#xff08;InsertSort&#xff09; 希尔排序&#xff08;ShellSort&#xff09; 计数排序&#xff08;CountSort&#xff09; 快速排序&#xff08;QuickSort&#xff09; 归并排序&#xff08;Merge Sort&a…

chatGPT4无法登录

遇到问题&#xff1a;chatgpt网站上点击登录&#xff08;log in),网站就会跳转并显示&#xff1a;unable to connect 解决方法&#xff1a;不要用亚洲节点&#xff0c;亚洲节点被全面封禁&#xff0c;在全局代理中可以换成美国的节点

故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,PLS偏最小二乘法的故障诊断(Matlab) 模型描述 偏最小二乘法(Partial Least Squares, PLS)是一种统计建模方法,用于建立变量之间的线性关系模型。它是对多元线性回归方法的扩展,特别适用于处理高维数据和具有多重共线性的数据集。…

Idea显示无法自动装配。找不到‘ xxx’类型的Bean

虽然只标红&#xff0c;不报错&#xff0c;但是看着非常别扭&#xff01; 原因&#xff1a; 当我们在使用Autowired注解的时候&#xff0c;默认requiredtrue,表示注入的时候bean必须存在&#xff0c;否则注入失败。 解决方案一&#xff1a; 在自动转配的注解后面添加(require…

AcWing 788. 逆序对的数量——算法基础课题解

AcWing 788. 逆序对的数量 题目描述 给定一个长度为 n 的整数数列&#xff0c;请你计算数列中的逆序对的数量。 逆序对的定义如下&#xff1a;对于数列的第 i 个和第 j 个元素&#xff0c;如果满足 i<j且 a[i]>a[j]&#xff0c;则其为一个逆序对&#xff1b;否则不是。…

HTML基础知识详解(上)(如何想知道html的全部基础知识点,那么只看这一篇就足够了!)

前言&#xff1a;在学习前端基础时&#xff0c;必不可少的就是三大件&#xff08;html、css、javascript &#xff09;&#xff0c;而HTML&#xff08;超文本标记语言——HyperText Markup Language&#xff09;是构成 Web 世界的一砖一瓦&#xff0c;它定义了网页内容的含义和…

一点点金融 5

一点点金融 5 怎么判断是短期回撤&#xff0c;还是趋势反转&#xff1f;市场行为和价格波动背后的深层次原因是什么&#xff1f;1. 成交密度与价格区间2. 投资者心理与市场情绪3. 供需动态4. 价格波动的自我实现性挖掘技术策略的原理分析步骤交易策略实施风险管理 技术分析者怎…

深入探索MySQL:成本模型解析与查询性能优化,及未来深度学习与AI模型的应用展望

码到三十五 &#xff1a; 个人主页 在数据库管理系统中&#xff0c;查询优化器是一个至关重要的组件&#xff0c;它负责将用户提交的SQL查询转换为高效的执行计划。在MySQL中&#xff0c;查询优化器使用了一个称为“成本模型”的机制来评估不同执行计划的优劣&#xff0c;并选择…

获取天翼网关TEWA-708E超级管理员密码

Download RouterPassView 参考&#xff1a;破解光猫超级管理员密码&#xff08;网关型号&#xff1a;TEWA-708E&#xff09; - 知乎

华清远见STM32MP157开发板助力嵌入式大赛ST赛道MPU应用方向项目开发

第七届&#xff08;2024&#xff09;全国大学生嵌入式芯片与系统设计竞赛&#xff08;以下简称“大赛”&#xff09;已经拉开帷幕&#xff0c;大赛的报名热潮正席卷而来。嵌入式大赛截止今年已连续举办了七届&#xff0c;为教育部认可的全国普通高校大学生国家级A类赛事&#x…

复杂度的讲解

1.算法效率 如何衡量一个算法的好坏&#xff1f;从两个维度&#xff0c;时间和空间&#xff08;算法运行的快慢&#xff0c;消耗的空间大不大&#xff09;。因为计算机硬件领域的高速发展&#xff0c;如今计算机的存储量已经达到了一个很高的程度&#xff0c;所以现在我们一般…

MyBatis的xml实现方式

1、该项目引入的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…