【1】关于ViewModel

ViewModel是Jetpack AAC的重要组件,同时也有一个同名抽象类。 ViewModel,意为 视图模型,即为界面准备数据的模型。简单理解就是,ViewModel为UI层提供数据。

  • 官方文档定义如下:
  • ViewModel 以注重生命周期的方式存储和管理界面相关的数据。(作用)
  • ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存。(特点)

到这里,你可能还是不清楚ViewModel到底是干啥的,别急,往下看。

①背景引出:

在详细介绍ViewModel前,先来看下背景和问题点。

Activity可能会在某些场景(例如屏幕旋转)销毁和重新创建界面,那么存储在其中的界面相关数据都会丢失。例如,界面含用户信息列表,因配置更改而重新创建Activity 后,新 Activity必须重新请求用户列表,这会造成资源的浪费。能否直接恢复之前的数据呢?对于简单的数据,Activity 可以使用onSaveInstanceState() 方法保存 然后从 onCreate()中的Bundle恢复数据,但此方法仅适合可以序列化再反序列化的少量数据(IPC对Bundle有1M的限制),而不适合数量可能较大的数据,如用户信息列表或位图。那么如何做到 因配置更改而新建Activity后的数据恢复呢?

UI层(如 Activity 和 Fragment)经常需要通过逻辑层(如MVP中的Presenter)进行异步请求,可能需要一些时间才能返回结果,如果逻辑层持有UI层应用(如context),那么UI层需要管理这些请求,确保界面销毁后清理这些调用以避免潜在的内存泄露,但此项管理需要大量的维护工作。 那么如何更好的避免因异步请求带来的内存泄漏呢?

  • 这时候ViewModel就闪亮出场了——ViewModel用于代替MVP中的Presenter,为UI层准备数据,用于解决上面两个问题。

②特点

1. 生命周期长于Activity

这是官方给的图。

看到在因屏幕旋转而重新创建Activity后,ViewModel对象依然会保留。 只有Activity真正Finish的时ViewModel才会被清除。

也就是说,因系统配置变更Activity销毁重建,ViewModel对象会保留并关联到新的Activity。而Activity的正常销毁(系统不会重建Activity)时,ViewModel对象是会清除的。

那么很自然的,因系统配置变更Activity销毁重建,ViewModel内部存储的数据 就可供重新创建的Activity实例使用了。这就解决了第一个问题。

  • 同样都是生命周期中的onDestroy为什么上一个没有没有销毁ViewModel而下一个却销毁了呢?

当Activity 处于前台的时候被销毁了,那么得到的 ViewModel 是之前实例过的 ViewModel;如果 Activity
处于后台时被销毁了,那么得到的 ViewModel 不是同一个。举例说,如果 Activity因为配置发生变化而被重建了,那么当重建的时候,ViewModel是之前的实例;如果因为长期处于后台而被销毁了,那么重建的时候,ViewModel就不是之前的实例了。而上一个onDestroy是前台的销毁,而后一个是后台的onDestroy

2. 不持有UI层引用
我们知道,在MVP的Presenter中需要持有IView接口来回调结果给界面。

而ViewModel是不需要持有UI层引用的,那结果怎么给到UI层呢?答案就是使用上一篇中介绍的基于观察者模式的LiveData。 并且,ViewModel也不能持有UI层引用,因为ViewModel的生命周期更长。

所以,ViewModel不需要也不能 持有UI层引用,那么就避免了可能的内存泄漏,同时实现了解耦。这就解决了第二个问题。

【2】如何使用:

①思路:

  • 导入依赖
  • 继承ViewModel自定义MyViewModel
  • 在MyViewModel中编写获取UI数据的逻辑
  • 使用LiveData将获取到的UI数据抛出
  • 在Activity/Fragment中使用ViewModelProvider获取MyViewModel实例
  • 观察MyViewModel中的LiveData数据,进行对应的UI更新。

举个例子,如果您需要在Activity中显示用户信息,那么需要将获取用户信息的操作分放到ViewModel中,代码如下:

public class UserViewModel extends ViewModel {private MutableLiveData<String> userLiveData ;private MutableLiveData<Boolean> loadingLiveData;public UserViewModel() {userLiveData = new MutableLiveData<>();loadingLiveData = new MutableLiveData<>();}//获取用户信息,假装网络请求 2s后 返回用户信息public void getUserInfo() {loadingLiveData.setValue(true);new AsyncTask<Void, Void, String>() {@Overrideprotected void onPostExecute(String s) {loadingLiveData.setValue(false);userLiveData.setValue(s);//抛出用户信息}@Overrideprotected String doInBackground(Void... voids) {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}String userName = "AAAAAABBBBBBBBBBBBCCCCCCCCC";return userName;}}.execute();}public LiveData<String> getUserLiveData() {return userLiveData;}public LiveData<Boolean> getLoadingLiveData() {return loadingLiveData;}
}

UserViewModel继承ViewModel,然后逻辑很简单:假装网络请求 2s后 返回用户信息,其中userLiveData用于抛出用户信息,loadingLiveData用于控制进度条显示。

再看UI层:

public class UserActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);...Log.i(TAG, "onCreate: ");TextView tvUserName = findViewById(R.id.textView);ProgressBar pbLoading = findViewById(R.id.pb_loading);//获取ViewModel实例ViewModelProvider viewModelProvider = new ViewModelProvider(this);UserViewModel userViewModel = viewModelProvider.get(UserViewModel.class);//观察 用户信息userViewModel.getUserLiveData().observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {// update ui.tvUserName.setText(s);}});userViewModel.getLoadingLiveData().observe(this, new Observer<Boolean>() {@Overridepublic void onChanged(Boolean aBoolean) {pbLoading.setVisibility(aBoolean?View.VISIBLE:View.GONE);}});//点击按钮获取用户信息findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {userViewModel.getUserInfo();}});}@Overrideprotected void onStop() {super.onStop();Log.i(TAG, "onStop: ");}@Overrideprotected void onDestroy() {super.onDestroy();Log.i(TAG, "onDestroy: ");}
}

页面有个按钮用于点击获取用户信息,有个TextView展示用户信息。 在onCreate()中先 创建ViewModelProvider实例,传入的参数是ViewModelStoreOwner,Activity和Fragment都是其实现。然后通过ViewModelProvider的get方法 获取ViewModel实例,然后就是 观察ViewModel中的LiveData。

②总结:

  • ViewModel的使用很简单,作用和原来的Presenter一致。只是要结合LiveData,UI层观察即可。

  • ViewModel的创建必须通过ViewModelProvider。

  • 注意到ViewModel中没有持有任何UI相关的引用。

  • 旋转手机重建Activity后,数据确实恢复了。

参考:鸿祥_AAC_ViewModel

Jetpack之ViewModel讲解相关推荐

  1. Android Jetpack组件ViewModel基本使用和原理分析

    本文整体流程:首先要知道什么是 ViewModel,然后演示一个例子,来看看 ViewModel 是怎么使用的,接着提出问题为什么是这样的,最后读源码来解释原因! 1.什么是ViewModel 1.1 ...

  2. Lifecycle、LiveData、ViewModel讲解之Lifecycle

    Lifecycle.LiveData.ViewModel介绍 在 Android 框架中定义的大多数应用组件都存在生命周期.生命周期由操作系统或进程中运行的框架代码管理.它们是 Android 运作方 ...

  3. Android Jetpack 之 ViewModel

    前言 在 Android 中,ViewModel 的作用就是在 UI 控制器( 如 Activity.Fragment)的生命周期中保存和管理 UI 相关的数据.ViewModel 保存的数据在配置更 ...

  4. jetpack之ViewModel

    ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据.ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存. 摘自官方文档 Android 框架可以管理界面控制器(如 Act ...

  5. Android Jetpack之DataBinding+ViewModel+LiveData+Room

    Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 前言 Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减 ...

  6. android jetpack ViewModel 报错解决方法

    android  jetpack 的viewmodel 部分,在activity里面写以下这行代码时会报错的解决方法: myViewModel = new ViewModelProvider(this ...

  7. ViewModel优雅的弹加载窗和获取Context

    前言 目前安卓开发一般都是用的mvvm模式,Jetpack的ViewModel是必不可少的一部分,而vm的生命周期要比Activity和Fragment长的,所以其一般不推荐其直接持有A或F,因为可能 ...

  8. android mvvm框架搭建_轻松搭建基于JetPack组件的MVVM框架

    原文链接:轻松搭建基于JetPack组件的MVVM框架 - 掘金 Brick github gitee 介绍 辅助android开发者搭建基于JetPack组件构建MVVM框架的注解处理框架.通过注解 ...

  9. 架构演进|研究mvp到mvvm(传统架构mvvm和Jetpack下的区别)

    mvp.mvvm架构演进|研究 MVP架构实现 定义数据结构类型 MVP架构改进--反射获取泛型类型实例 MVVM架构基础 配置DataBinding 添加Jetpack组件 MVVM架构下的项目层次 ...

最新文章

  1. web开发性能优化---用户体验篇
  2. java中BigDecimal的常见用法
  3. c语言总是说有一个错误,我的电脑上的c语言为何老有一个错误
  4. Java基础面试16问
  5. 见识可能比聪明更重要!
  6. 中信银行MySQL面试_【深圳中信银行信用卡中心面试】面试题_面试经验_面试流程-看准网...
  7. 以太坊Dapp项目-网页钱包开发手册
  8. oracle set autocommit,Oracle Sqlplus SET AUTOCOMMIT
  9. Oracle学习笔记:oracle的启动过程
  10. 每天10个Linux命令三
  11. requests第三方库在测试中的使用
  12. 搭建属于自己的复古传奇私服
  13. 全国大学生智能汽车竞赛山东省赛区获奖队伍信息
  14. 单龙芯3A3000-7A1000PMON研究学习-(1)硬件原理图
  15. 1553B 协议详解
  16. 请你讲讲分布式系统中的限流器一般如何实现?
  17. 嵌入式设计与开发项目-ADC键盘扫描程序设计
  18. socket读写返回值的处理
  19. 连接大智慧数据库接口
  20. 小豹子带你看源码:Java 线程池(三)提交任务

热门文章

  1. 记录学习前端知识的旅程【4】
  2. 实验室云检验信息系统(云LIS源码)
  3. 广药计算机科学与技术怎么样,广东药科大学怎么样 在全国排名多少好不好
  4. 路由器NAT功能配置简介
  5. 论述一款软件的界面设计与设计重点是什么?
  6. Unity2018中关于多道具拾取,按键提示显示问题
  7. 拼多多2018校招编程题汇总 - 题解
  8. 四化智造MES(WEB)与金蝶云星空对接集成业务订单列表查询连通生产入库单新增(生产入库确认退货-生产退库单-TEST)
  9. Scrapy小白爬取智联校园招聘
  10. 松下DP-8016P在win7下不能打印的解决方案