ViewModel

ViewModel的引入

如果系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失。例如,应用的某个 Activity 中可能包含用户列表。因配置更改而重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。

架构组件为界面控制器提供了 ViewModel 辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。

实现ViewModel

  1. package com.zyb.viewmodeltest;
  2. import androidx.lifecycle.ViewModel;
  3. public class MyViewModel extends ViewModel {
  4. public int num = 0;
  5. }

从 Activity 访问该列表,如下所示:

  1. package com.zyb.viewmodeltest;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.Button;
  6. import android.widget.TextView;
  7. import androidx.lifecycle.ViewModelProviders;
  8. public class MainActivity extends AppCompatActivity {
  9. MyViewModel myViewModel;
  10. Button button1,button2;
  11. TextView showScore;
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main);
  16. myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  17. button1 = findViewById(R.id.button);
  18. button2 = findViewById(R.id.button2);
  19. showScore = findViewById(R.id.textView);
  20. showScore.setText(myViewModel.num+"");
  21. button1.setOnClickListener(new View.OnClickListener() {
  22. @Override
  23. public void onClick(View v) {
  24. myViewModel.num++;
  25. showScore.setText(myViewModel.num+"");
  26. }
  27. });
  28. button2.setOnClickListener(new View.OnClickListener() {
  29. @Override
  30. public void onClick(View v) {
  31. myViewModel.num += 2;
  32. showScore.setText(myViewModel.num+"");
  33. }
  34. });
  35. }
  36. }

ui:



功能:点击+1,数字+1,点击+2,数字在原来基础上+2

优点:不用我们保存之前加过数字的状态,因为在配置更改期间会自动保留 ViewModel 对象

缺点: showScore.setText();出现过多,代码累赘,setOnClickListener出现过多代码不好看

LiveData

使用 LiveData 具有以下优势:

确保界面符合数据状态

LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。观察者可以在每次发生更改时更新界面,而不是在每次应用数据发生更改时更新界面。

不会发生内存泄露

观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

不会因 Activity 停止而导致崩溃

如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

不再需要手动处理生命周期

界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

数据始终保持最新状态

如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

适当的配置更改

如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

共享资源

您可以使用单一实例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。有关详情,请参阅扩展 LiveData。

实现LiveData

  1. package com.zyb.livedatatest;
  2. import androidx.lifecycle.MutableLiveData;
  3. import androidx.lifecycle.ViewModel;
  4. public class MyViewModel extends ViewModel {
  5. private MutableLiveData<Integer> num;
  6. public MutableLiveData<Integer> getNum() {
  7. if(num == null){
  8. num = new MutableLiveData<>();
  9. num.setValue(0);
  10. }
  11. return num;
  12. }
  13. public MutableLiveData<Integer> addNum(int n){
  14. num.setValue(num.getValue()+n);
  15. return num;
  16. }
  17. }

从 Activity 访问该列表,如下所示:

  1. package com.zyb.livedatatest;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import androidx.lifecycle.Observer;
  4. import androidx.lifecycle.ViewModel;
  5. import androidx.lifecycle.ViewModelProviders;
  6. import android.os.Bundle;
  7. import android.view.View;
  8. import android.widget.ImageButton;
  9. import android.widget.TextView;
  10. public class MainActivity extends AppCompatActivity {
  11. ImageButton redButton,blueButton;
  12. TextView score;
  13. MyViewModel myViewModel;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. redButton = findViewById(R.id.imageButton);
  19. blueButton = findViewById(R.id.imageButton3);
  20. score = findViewById(R.id.textView);
  21. myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  22. //观察数据是否改变,改变就重写
  23. myViewModel.getNum().observe(this, new Observer<Integer>() {
  24. @Override
  25. public void onChanged(Integer integer) {
  26. score.setText(integer+"");
  27. }
  28. });
  29. redButton.setOnClickListener(new View.OnClickListener() {
  30. @Override
  31. public void onClick(View v) {
  32. myViewModel.addNum(1);
  33. }
  34. });
  35. blueButton.setOnClickListener(new View.OnClickListener() {
  36. @Override
  37. public void onClick(View v) {
  38. myViewModel.addNum(-1);
  39. }
  40. });
  41. }
  42. }

ui:

功能:左边+1,右边-1

优点:将setText()减少到一句

缺点:setOnClickListener出现过多代码不好看

DataBinding

在buid.gradle开启数据绑定:



之后重新构建项目sync

进入activity_main.xml中点击

之后会多两个标签和

  1. package com.zyb.databindingtest;
  2. import androidx.lifecycle.MutableLiveData;
  3. import androidx.lifecycle.ViewModel;
  4. public class MyViewModel extends ViewModel {
  5. MutableLiveData<Integer> cnt;
  6. public MutableLiveData<Integer> getCnt() {
  7. if(cnt == null){
  8. cnt = new MutableLiveData<>();
  9. cnt.setValue(0);
  10. }
  11. return cnt;
  12. }
  13. public void add(int n){
  14. cnt.setValue(cnt.getValue()+n);
  15. }
  16. }

MainActivity.java

  1. package com.zyb.databindingtest;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import androidx.databinding.DataBindingUtil;
  4. import androidx.lifecycle.ViewModel;
  5. import androidx.lifecycle.ViewModelProvider;
  6. import androidx.lifecycle.ViewModelProviders;
  7. import android.os.Bundle;
  8. import com.zyb.databindingtest.databinding.ActivityMainBinding;
  9. public class MainActivity extends AppCompatActivity {
  10. //绑定1:将界面对象绑定到控制器的ActivityMainBinding对象中(可以调用bind.xml标签名)
  11. ActivityMainBinding bind;//注意这个类的名字和你Java文件的名字相同,不是固定的
  12. MyViewModel myViewModel;
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. bind = DataBindingUtil.setContentView(this,R.layout.activity_main);
  17. myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  18. //绑定2:将屏幕数据和控件的xml绑定
  19. bind.setData1(myViewModel);//setData1是因为在xml那个数据的name自己设定的data1,所以这setData1也是不固定的
  20. //这句很重要,相当于之前设置的观察者语句
  21. bind.setLifecycleOwner(this);
  22. }
  23. }

ui:



功能:显示点击按钮次数

优点:控制器代码减少,分工更明确

activity_main.xml变化:这个写法有点像javaweb的模板引擎thymeleaf







最后的

thymeleaf相关图:

相关变化图:

最原始的,通过findViewById将单个组件的引用和控制器来连接起来,数据显示和变化都在控制器中



加入ViewModel之后将页面数据(UIData)单独提出来封装



加入LiveData,将之前提出来的UIData换为LiveData类型的,因为它满足观察者类型,可以减少setText的书写,降低代码耦合性



加入DataBinding将数据操作绑定到相关界面的xml文件中,减少控制器的代码量,分工更明确了

ui

参考链接

[android开发者官网](https://developer.android.google.cn/jetpack)
[视频](https://www.bilibili.com/video/av50954019?p=11)

ViewModel、LiveData、DataBinding的更多相关文章

  1. Android 架构组件-Lifecycle、LiveData、ViewModel

    Lifecycle Lifecycle组件包括LifecycleOwner.LifecleObserver,能方便监听Activity或者Fragment的生命周期. 步骤: 1.实现Lifecycl ...

  2. 转 Android Lifecycle、ViewModel和LiveData

    转自:https://www.jianshu.com/p/982545e01d0a 1.概述 在I / O '17的时候,其中一个重要的主题是Architecture Components.这是一个官 ...

  3. 利刃 MVVMLight 2:Model、View、ViewModel结构以及全局视图模型注入器的说明

         上一篇我们已经介绍了如何使用NuGet把MVVMLight应用到我们的WPF项目中.这篇我们来了解下一个基本的MVVMLight框架所必须的结构和运行模式. MVVMLight安装之后,我们 ...

  4. MVC到底使用哪种方式传递Model,在ViewData、ViewBag、PartialView、TempData、ViewModel、Tuple之间取舍

    在"MVC控制器传递多个Model到视图,使用ViewData, ViewBag, 部分视图, TempData, ViewModel, Tuple"中,体验了使用不同的方式传递多 ...

  5. 迷你MVVM框架 avalonjs 学习教程2、模块化、ViewModel、作用域

    一个项目是由许多人分工写的,因此必须要合理地拆散,于是有了模块化.体现在工作上,PM通常它这为某某版块,某某频道,某某页面.某一个模块,必须是包含其固有的数据,样式,HTML与处理逻辑.在jQuery ...

  6. ViewModel、ViewData、ViewBag、TempData、Session之间的区别和各自的使用方法

    ViewModel    ViewModel 是一个用来渲染 ASP.NET MVC 视图的强类型类,可用来传递来自一个或多个视图模型(即类)或数据表的数据.可将其看做一座连接着模型.数据和视图的桥梁 ...

  7. MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录

    注:文章内容都是摘录性文字,自己阅读的一些笔记,方便日后查看. MVC MVC(Model-View-Controller),M 是指业务模型,V 是指用户界面,C 则是控制器,使用 MVC 的目的是 ...

  8. 转:界面之下:还原真实的 MVC、MVP、MVVM 模式

    前言 做客户端开发.前端开发对MVC.MVP.MVVM这些名词不了解也应该大致听过,都是为了解决图形界面应用程序复杂性管理问题而产生的应用架构模式.网上很多文章关于这方面的讨论比较杂乱,各种MV*模式 ...

  9. [转]MVC、MVP、MVVM

    界面之下:还原真实的 MVC.MVP.MVVM 模式 [日期:2015-10-28] 来源:github.com/livoras  作者:戴嘉华 [字体:大 中 小]   前言 做客户端开发.前端开发 ...

随机推荐

  1. Linux終端一行命令发送邮件

    近期由于经常需要给别人发送邮件,每次都要打开QQ邮箱觉得非常麻烦.想到Linux终端可以自定义命令,加上python可以实现邮件发送功能,于是自己写了一个终端send + 文件地址的命令. 首先贴上p ...

  2. git 报错和解决

    1.报错 fatal: refusing to merge unrelated histories 解决 两个不相干的库进行合并,需要进行强制合并 git pull origin master --a ...

  3. 洛谷P1086 花生采摘

    https://www.luogu.org/problem/P1086 #include <bits/stdc++.h> using namespace std; typedef long ...

  4. 训练20191009 2018-2019 ACM-ICPC, Asia East Continent Finals

    2018-2019 ACM-ICPC, Asia East Continent Finals 总体情况 本次训练共3小时20分钟,通过题数4. 解题报告 D. Deja vu of - Go Play ...

  5. Allegro---层叠结构设置

     PCB层叠结构 层叠结构是一个非常重要的问题,不可忽视,一般选择层叠结构考虑以下原则: ·元件面下面(第二层)为地平面,提供器件屏蔽层以及为顶层布线提供参考平面: ·所有信号层尽可能与地平面相邻: ...

  6. SpringMVC进行Ajax请求页面显示乱码

    最近在项目的使用过程中发现在springmvc的项目中,使用返回页面的请求方式,数据都能正常显示,但是对于ajax的请求,始终显示乱码. 首先第一种是因为我们在web.xml中配置了spring的字符 ...

  7. Spring Boot的27个注解【核心】

    导读[约定大于配置] Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务 ...

  8. SQLServer2008不允许保存更改错误解决办法

    SQLServer2008不允许保存更改错误解决办法 今天在运行sql server 2008时候提示不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法. 一.启动SQL Server ...

  9. 实用sql语句合集

    1. 将选取A表的name字段  然后选择A表和B表,最后进行id相等比较 最终得到的是合集 $res = \DB::select("SELECT name FROM users,car_a ...

  10. oracle分组并在组内排序

    根据c1,c2分组,并且根据c3排序,取第一行select tt.*  from (select row_number() over(partition by c1, c2 order by c3 d ...