Android中级——MVVM
MVVM
- MVVM是什么?
- MVVM实现
- 前提
- Model
- ViewModel
- View
MVVM是什么?
Model-View-ViewMode架构,可看作MVP改进版,将此前Presenter的逻辑操作交给ViewMode中的Binder去处理

- Mode:封装数据存储及相关操作逻辑,与MVC/MVP不同的是会提供一系列实体类与UI绑定,ViewModel修改这些数据后将数据变化告诉View
- View:处理界面逻辑但不参与业务逻辑,显示ViewModel提供的数据
- ViewModel:视图模型与视图状态的合称,为View提供一个可供显示的数据模型并收集、处理这些数据,内部的Binder用于双向绑定,还可包含多个Child ViewModel
MVVM实现
前提
在build.gradle中android节点添加如下代码(最低SDK版本为API7,Gradle版本为1.5.0-alpha1)
dataBinding{enabled = true
}
Model
创建数据实体类LoginInfo
- 继承BaseObservable
- getXXX()方法通过@Bindable注解表示该方法所返回的数据被修改时会更新UI
- setXXX()方法调用notifyPropertyChanged()告诉DataBinding该字段被更改
public class LoginInfo extends BaseObservable {private String mUser;private String mPassword;public LoginInfo(String user, String password) {mUser = user;mPassword = password;}@Bindablepublic String getUser() {return mUser;}public void setUser(String user) {mUser = user;notifyPropertyChanged(BR.user);}@Bindablepublic String getPassword() {return mPassword;}public void setPassword(String password) {mPassword = password;notifyPropertyChanged(BR.password);}
}
ViewModel
LoginModel封装维护LoginInfo、点击事件、文本改变事件
public class LoginModel {private static final String DEF_USER = "song";private static final String DEF_PASSWORD = "123";public LoginInfo mInfo;private OnLoginListener mListener;public LoginModel(OnLoginListener listener) {mListener = listener;mInfo = new LoginInfo("", "");}public TextWatcher getUserTextWatcher() {return new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {mInfo.setUser(s.toString());}};}public TextWatcher getPasswordTextWatcher() {return new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {mInfo.setPassword(s.toString());}};}public interface OnLoginListener {void onLoginSuccess();void onLoginFail();}public void onLoginClick(View view) {if (mInfo.getUser().equals(DEF_USER) && mInfo.getPassword().equals(DEF_PASSWORD)) {mListener.onLoginSuccess();} else {mListener.onLoginFail();}}
}
View
xml文件根节点变为layout,布局分为
- 数据部分:声明所使用到的数据实体类以及构造该对象时的引用名
- UI部分:常规控件,可直接使用数据实体类对象中的字段、方法
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="model"type="com.demo.demo0.LoginModel" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:addTextChangedListener="@{model.getUserTextWatcher}"android:hint="User"android:text="@{model.mInfo.getUser}" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:addTextChangedListener="@{model.getPasswordTextWatcher}"android:hint="Password"android:text="@{model.mInfo.getPassword}" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="@{model.onLoginClick}"android:text="Login" /></LinearLayout></layout>
MainActivity开启线程3秒后修改数据会显示在UI
- 通过DataBindingUtil.setContentView设置布局,布局名字为R.layout.ab_cd,则对应类为AbCdBinding,为其设置Model
public class MainActivity extends AppCompatActivity implements LoginModel.OnLoginListener {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);LoginModel model = new LoginModel(this);binding.setModel(model);new Thread(new Runnable() {@Overridepublic void run() {SystemClock.sleep(3000);model.mInfo.setUser("New User");model.mInfo.setPassword("New Password");}}).start();}@Overridepublic void onLoginSuccess() {Log.d(TAG, "onLoginSuccess: ");}@Overridepublic void onLoginFail() {Log.d(TAG, "onLoginFail: ");}
}
相关文章:
Android中级——MVVM
MVVM MVVM是什么?MVVM实现前提ModelViewModelView MVVM是什么? Model-View-ViewMode架构,可看作MVP改进版,将此前Presenter的逻辑操作交给ViewMode中的Binder去处理 Mode:封装数据存储及相关操作逻辑,与MV…...
AIGC:引领人工智能和游戏产业融合的里程碑
目录 引言: 一、AIGC简介 二、AIGC的意义和作用 三、AIGC的未来展望 四、AIGC的影响和成果 五、结论 引言: 人工智能技术的快速发展在过去几年中引起了全球范围内的广泛关注和热议。其中,AIGC(Artificial Intelligence and G…...
ubuntu安装rust教程
参考【Rust】Linux上安装Rust开发环境 sudo apt-get install curl# 注意,不开代理很可能下不到,一直报403 export RUSTUP_DIST_SERVERhttps://mirrors.ustc.edu.cn/rust-static export RUSTUP_UPDATE_ROOThttps://mirrors.ustc.edu.cn/rust-static/rustu…...
iOS UIWebView与WKWebView 那些事
一、前言介绍 UIWebView 是 iOS 2 中推出的网页容器,UIWebView是最占内存的控件;直到 iOS 8 以后,苹果推出了 WebKit 框架,其中 WKWebView 正式被推出来接替 UIWebView 的位置;iOS 12 中,苹果正式弃用 UIWebView,要求开发者用 WKWebView 全面替换 UIWebView,apple 官方…...
wps/word 之 word中的两个表格 如何合并成为一个表格(已解决)
第一步:新建两个表格: 如何实现上面的两个表格合并呢? 分别选定每个表格,然后鼠标右键---》表格属性 在表格属性中的 表格---》选择 无文字环绕。 第二个表格按照同样的方法 设置 无文字环绕。 然后将中的文本行删去即可以了。选…...
02HTML功能元素
1.功能元素 1.1.列表标签 列表标签的作用: 给一堆数据添加列表语义, 也就是告诉搜索引擎告诉浏览器这一堆数据是一个整体 - HTML中列表标签的分类 无序列表(最多)(unordered list) 有序列表(最少)(ordered list) 定义列表(其次)(definition list) 1.1.1.无序列…...
并发编程-延时队列DelayQueue
数据结构学习网站: Data Structure Visualization 思维导图 DelayQueue (延时队列) DelayQueue 是一个支持延时获取元素的阻塞队列 , 内部采用优先队列 PriorityQueue 存储元素,同时元素必须实现 Delayed 接口&#x…...
Python之哈希表-遍历和有序性
Python之哈希表-遍历和有序性 有序性 字典元素是按照key的hash值无序存储的。 但是,有时候我们却需要一个有序的元素顺序,Python 3.6之前,使用OrderedDict类可以做到,3.6开 始dict自身支持。 d1 {b:33, c:True, d:[1], f:234…...
Oracle数据库完整卸载的完整步骤
时间:2023-03-15来源:系统城装机大师作者:佚名 1、停止所有Oracle服务 进入计算机管理,在服务中,找到oracle开头的所有服务,右击选择停止。 快捷键:ctrlshiftesc打开任务管理器 文章来源 Or…...
HP OfficeJet Pro 8020 如何更换碳粉盒
环境: HP OfficeJet Pro 8020 问题描述: HP OfficeJet Pro 8020 如何更换碳粉盒 解决方案: 更换碳粉盒 更换所有墨水不足的碳粉盒或空碳粉盒。 1.打开前挡盖,然后提起碳粉盒检修门。 打开打印机门 2.等待笔架停止后再继续操作…...
【Javascript】基础数据类型
目录 基础数据类型 1.number 字面量声明 数字对象方式声明 整数判断 指定返回小数位数 NaN-表示非数字值 浮点精度 解决误差 String 字面量声明 数字对象声明 连接运算符 获取长度 大小写转换 转换成大写 转换成小写 编辑 移除空白 获取单字符 编辑 截…...
【C语言】进阶——程序编译
目录 一:🔒程序环境 程序的翻译环境和执行环境 💡1.1翻译环境 预编译阶段: 编译阶段: 汇编阶段: 链接阶段: 💡1.2运行环境 二:🔒预处理详解 &…...
记录阿里云服务器(Centos7.9)部署Thingsboard(3.4.2)遇到的一些问题
记录编译Thingsboard遇到的一些问题 部署了一个thingsboard项目到阿里云服务器上,历时十一天,遇到了很多困难,国内关于Thingsboard的资料确实很少,所以想着写一篇博客记录一下,或许能够给以后编译遇到类似问题的人一些…...
docker更新容器映射端口
一个容器已经暴露了一个端口被外界使用,但是这个端口被公司不允许使用,需要修改为其他的端口,怎么办? 1、删除原容器,重启新容器 删除已启动容器,从镜像重启新容器。2、修改原容器配置文件 3、生成镜像&…...
Pr快捷键
Pr快捷键 以下快捷键都是在英文输入法下 一、隐藏顶部项目信息 Ctrl\ 注意:是反斜杠,回车上面的按键二、单独放大窗口 选中面板按~键三、放大/缩小时间轴素材 \四、自动选中素材 序列菜单-选择跟随播放指示器五、快速定位间隙 SHIFT鼠标拖动素材 …...
94. 递归实现排列型枚举
题目: 94. 递归实现排列型枚举 - AcWing题库 思路: 1.全排列问题(坑位问题)---->递归搜索树---->用dfs深度优先搜索。 2. u表示当前坑位,state[u]表示坑位u存储的数据。因为不同坑位的数据不可以重复&#…...
白水三佳电脑ERP部署
安装宝塔面板,有这个方便很多,可以省下3天的环境部署时间。 移动端, 先取移动版的压缩包,上传至服务器/www/wwwroot/目录下面,直接解压到当前目录后会生成/www/wwwroot/m/的目录,移动版就在这里面了。以下…...
电流监测芯片SGM8199A2应用电路设计
SGM8199是一系列具有电压输出功能的双向电流监测芯片,用于监测共模电压范围内分流电阻上的压降,而不受电源电压的影响。该器件具有-0.1V至26V的宽共模电压范围输入。低偏移使得在监测电流时允许分流器上的满量程最大压降为10mV。SGM8199系列提供三种固定…...
第十五章 I/O输入输出
15,1输入输出流 流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流两种。I/O(Input/Output,(输出)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。虽然 I/O 流疆盘文件存取有关,但是程序的源和目的…...
进程(0)——计算机的中的软硬件【Linux】
进程(0)——计算机的中的软硬件【Linux】 一.硬件:1.1 冯诺依曼结构:1.2 存储金字塔1.2.1输入设备和存储器:1.2.2输出设备和存储器: 二.软件:2.1 操作系统2.1.1 如何理解管理: 博主自…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
