本篇文章给大家谈谈利用JavaScript数据绑定实现一个简单的MVVM库,以及js怎么绑定数据的知识点,同时本文还将给你拓展5.MVVM模式、Android--------MVC,MVP和MVVM架
本篇文章给大家谈谈利用 JavaScript 数据绑定实现一个简单的 MVVM 库,以及js怎么绑定数据的知识点,同时本文还将给你拓展5.MVVM 模式、Android -------- MVC,MVP 和 MVVM 架构设计模式、Android MVP,MVVM、Android MVVM 简单配置 --data Binding Library等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- 利用 JavaScript 数据绑定实现一个简单的 MVVM 库(js怎么绑定数据)
- 5.MVVM 模式
- Android -------- MVC,MVP 和 MVVM 架构设计模式
- Android MVP,MVVM
- Android MVVM 简单配置 --data Binding Library
利用 JavaScript 数据绑定实现一个简单的 MVVM 库(js怎么绑定数据)
MVVM 是 Web 前端一种非常流行的开发模式,利用 MVVM 可以使我们的代码更专注于处理业务逻辑而不是去关心 DOM 操作。目前著名的 MVVM 框架有 vue, avalon , angular 等,这些框架各有千秋,但是实现的思想大致上是相同的:数据绑定 + 视图刷新。出于好奇和一颗愿意折腾的心,我自己也沿着这个方向写了一个最简单的 MVVM 库 ( mvvm.js ),总共 2000 多行代码,指令的命名和用法与 vue 相似,在这里分享一下实现的原理以及我的代码组织思路。
思路整理
MVVM 在概念上是真正将视图与数据逻辑分离的模式,ViewModel 是整个模式的重点。要实现 ViewModel 就需要将数据模型(Model)和视图(View)关联起来,整个实现思路可以简单的总结成 5 点:
实现一个 Compiler 对元素的每个节点进行指令的扫描和提取;
实现一个 Parser 去解析元素上的指令,能够把指令的意图通过某个刷新函数更新到 dom 上(中间可能需要一个专门负责视图刷新的模块)比如解析节点
<p v-show="isShow"></p>
时先取得 Model 中 isShow 的值,再根据 isShow 更改node.style.display
从而控制元素的显示和隐藏;实现一个 Watcher 能将 Parser 中每条指令的刷新函数和对应 Model 的字段联系起来;
实现一个 Observer 使得能够对对象的所有字段进行值的变化监测,一旦发生变化时可以拿到最新的值并触发通知回调;
利用 Observer 在 Watcher 中建立一个对 Model 的监听 ,当 Model 中的一个值发生变化时,监听被触发,Watcher 拿到新值后调用在步骤 2 中关联的那个刷新函数,就可以实现数据变化的同时刷新视图的目的。
效果示例
首先粗看下最终的使用示例,与其他 MVVM 框架的实例化大同小异:
<div id="mobile-list">
<h1 v-text="title"></h1>
<ul>
<li v-for="item in brands">
<b v-text="item.name"></b>
<span v-show="showRank">Rank: {{item.rank}}</span>
</li>
</ul>
</div>
var element = document.querySelector(''#mobile-list'');
var vm = new MVVM(element, {
''title'' : ''Mobile List'',
''showRank'': true,
''brands'' : [
{''name'': ''Apple'', ''rank'': 1},
{''name'': ''Galaxy'', ''rank'': 2},
{''name'': ''OPPO'', ''rank'': 3}
]
});
vm.set(''title'', ''Top 3 Mobile Rank List''); // => <h1>Top 3 Mobile Rank List</h1>
模块划分
我把 MVVM 分成了五个模块去实现: 编译模块 Compiler 、解析模块 Parser 、视图刷新模块 Updater 、数据订阅模块 Watcher 和 数据监听模块 Observer 。流程可以简述为:Compiler 编译好指令后将指令信息交给解析器 Parser 解析,Parser 更新初始值并向 Watcher 订阅数据的变化,Observer 监测到数据的变化然后反馈给 Watcher ,Watcher 再将变化结果通知 Updater 找到对应的刷新函数进行视图的刷新。
上述流程如图所示:
下文就介绍下这五个模块实现的基本原理(代码只贴重点部分,完整的实现请到我的 Github 翻阅)
1. 编译模块 Compiler
Compiler 的职责主要是对元素的每个节点进行指令的扫描和提取。因为编译和解析的过程会多次遍历整个节点树,所以为了提高编译效率在 MVVM 构造函数内部先将 element
转成一个文档碎片形式的副本 fragment
编译对象是这个文档碎片而不应该是目标元素,待全部节点编译完成后再将文档碎片添加回到原来的真实节点中。
vm.complieElement
实现了对元素所有节点的扫描和指令提取:
vm.complieElement = function(fragment, root) {
var node, childNodes = fragment.childNodes;
// 扫描子节点
for (var i = 0; i < childNodes.length; i++) {
node = childNodes[i];
if (this.hasDirective(node)) {
this.$unCompileNodes.push(node);
}
// 递归扫描子节点的子节点
if (node.childNodes.length) {
this.complieElement(node, false);
}
}
// 扫描完成,编译所有含有指令的节点
if (root) {
this.compileAllNodes();
}
}
vm.compileAllNodes
方法将会对 this.$unCompileNodes
中的每个节点进行编译(将指令信息交给 Parser ),编译完一个节点后就从缓存队列中移除它,同时检查 this.$unCompileNodes.length
当 length === 0 时说明全部编译完成,可以将文档碎片追加到真实节点上了。
2. 指令解析模块 Parser
当编译器 Compiler 把每个节点的指令提取出来后就可以给到解析器解析了。每一个指令都有不同的解析方法,所有指令的解析方法只要做好两件事:一是将数据值更新到视图上(初始状态),二是将刷新函数订阅到 Model 的变化监测中。这里以解析 v-text
为例描述一个指令的大致解析方法:
parser.parseVText = function(node, model) {
// 取得 Model 中定义的初始值
var text = this.$model[model];
// 更新节点的文本
node.textContent = text;
// 对应的刷新函数:
// updater.updateNodeTextContent(node, text);
// 在 watcher 中订阅 model 的变化
watcher.watch(model, function(last, old) {
node.textContent = last;
// updater.updateNodeTextContent(node, text);
});
}
3. 数据订阅模块 Watcher
上个例子,Watcher 提供了一个 watch
方法来对数据变化进行订阅,一个参数是模型字段 model 另一个是回调函数,回调函数是要通过 Observer 来触发的,参数传入新值 last 和 旧值 old , Watcher 拿到新值后就可以找到 model 对应的回调(刷新函数)进行更新视图了。model 和 刷新函数是一对多的关系,即一个 model 可以有任意多个处理它的回调函数(刷新函数),比如:v-text="title"
和 v-html="title"
两个指令共用一个数据模型字段。
添加数据订阅 watcher.watch
实现方式为:
watcher.watch = function(field, callback, context) {
var callbacks = this.$watchCallbacks;
if (!Object.hasOwnProperty.call(this.$model, field)) {
console.warn(''The field: '' + field + '' does not exist in model!'');
return;
}
// 建立缓存回调函数的数组
if (!callbacks[field]) {
callbacks[field] = [];
}
// 缓存回调函数
callbacks[field].push([callback, context]);
}
当数据模型的 field 字段发生改变时,Watcher 就会触发缓存数组中订阅了 field 的所有回调。
4. 数据监听模块 Observer
Observer 是整个 mvvm 实现的核心基础,看过有一篇文章说 O.o (Object.observe) 将会引爆数据绑定革命,给前端带来巨大影响力,不过很可惜,ES7 草案已经将 O.o 给废弃了!目前也没有浏览器支持!所幸的是还有 Object.defineProperty
通过拦截对象属性的存取描述符(get 和 set) 可以模拟一个简单的 Observer :
// 拦截 object 的 prop 属性的 get 和 set 方法
Object.defineProperty(object, prop, {
get: function() {
return this.getValue(object, prop);
},
set: function(newValue) {
var oldValue = this.getValue(object, prop);
if (newValue !== oldValue) {
this.setValue(object, newValue, prop);
// 触发变化回调
this.triggerChange(prop, newValue, oldValue);
}
}
});
然后还有个问题就是数组操作 ( push, shift 等) 该如何监测?所有的 MVVM 框架都是通过重写该数组的原型来实现的:
observer.rewriteArrayMethods = function(array) {
var self = this;
var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto);
var methods = ''push|pop|shift|unshift|splice|sort|reverse''.split(''|'');
methods.forEach(function(method) {
Object.defineProperty(arrayMethods, method, function() {
var i = arguments.length;
var original = arrayProto[method];
var args = new Array(i);
while (i--) {
args[i] = arguments[i];
}
var result = original.apply(this, args);
// 触发回调
self.triggerChange(this, method);
return result;
});
});
array.__proto__ = arrayMethods;
}
这个实现方式是从 vue 中参考来的,觉得用的很妙,不过数组的 length 属性是不能够被监听到的,所以在 MVVM 中应避免操作 array.length
5. 视图刷新模块 Updater
Updater 在五个模块中是最简单的,只需要负责每个指令对应的刷新函数即可。其他四个模块经过一系列的折腾,把最后的成果交给到 Updater 进行视图或者事件的更新,比如 v-text
的刷新函数为:
updater.updateNodeTextContent = function(node, text) {
node.textContent = text;
}
v-bind:style
的刷新函数:
updater.updateNodeStyle = function(node, propperty, value) {
node.style[propperty] = value;
}
双向数据绑定的实现
表单元素的双向数据绑定是 MVVM 的一个最大特点之一:
其实这个神奇的功能实现原理也很简单,要做的只有两件事:一是数据变化的时候更新表单值,二是反过来表单值变化的时候更新数据,这样数据的值就和表单的值绑在了一起。
数据变化更新表单值 利用前面说的 Watcher 模块很容易就可以做到:
watcher.watch(model, function(last, old) {
input.value = last;
});
表单变化更新数据 只需要实时监听表单的值得变化事件并更新数据模型对应字段即可:
var model = this.$model;
input.addEventListenr(''change'', function() {
model[field] = this.value;
});
其他表单 radio, checkbox 和 select 都是一样的原理。
以上,整个流程以及每个模块的基本实现思路都讲完了,语言表达能力不太好,如有说的不对写的不好的地方,希望大家能够批评指正!
结语
折腾这个简单的 mvvm.js 是因为原来自己的框架项目中用的是 vue.js 但是只是用到了它的指令系统,一大堆功能只用到四分之一左右,就想着只是实现 data-binding 和 view-refresh 就够了,结果没找这样的 javascript 库,所以我自己就造了这么一个轮子。
虽说功能和稳定性远不如 vue 等流行 MVVM 框架,代码实现可能也比较粗糙,但是通过造这个轮子还是增长了很多知识的 ~ 进步在于折腾嘛!
目前我的 mvvm.js 只是实现了最本的功能,以后我会继续完善、健壮它,如有兴趣欢迎一起探讨和改进~
源代码传送门: https://github.com/tangbc/sugar
5.MVVM 模式
#1. MVVM 简介
###1. MVC
针对客户端应用开发 AngularJS 吸收了传统的 MVC 基本原则。MVC (Model-View-Controll) 设计模式针对不同的人可能意味不同的东西,AngularJS 并不执行传统意义上的 MVC,更接近于 MVVM。 ###2.MVVM(js 分层思想)
MVVM 模式是 Model-View-ViewMode 模式的简称。由视图 (View)、视图模型 (ViewModel)、模型 (Model) 三部分组成,通过这三部分实现UI逻辑
、呈现逻辑和状态控制
、数据与业务逻辑
的分离。
###3. scope: [skəʊp] 作用域
Model 将和 ViewModel 互动 (通过 $scope对象
),将监听 Model 的变化。
互动需要监听事件,通过$scope实现
VIew和路由
||$routeProvider对象
###3. view 作用 这些可以通过 View 来发送和渲染,由 HTML 来展示你的代码。 View 可以通过 $routeProvider 对象来支配,所以你可以深度的链接和组织你的 View 和 Controller,将他们变成导航 URL。
AngualrJS 同时提供了无状态的 Controller,可以用来初始化和控制 $scope 对象。
###4. model 的作用 Model 与 MVC 模式一样,Model 用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。
它具有对数据直接访问的权利,例如对数据库的访问,Model不依赖于View和ViewModel
,也就是说,模型不关心会被如何显示或是如何被操作,模型也不能包含任何用户使用的与界面相关的逻辑
。
###5. ViewModel (很重要的)
ViewModel 是一个用来提供特别数据和方法从而维护指定 view 的对象,。
ViewModel 是 $scope 的对象,只存在于 AnguarJS 的应用中。
$scope 只是一个简单的 js 对象,这个对象使用简单的 API 来侦测和广播状态变化。
###6. Controller 作用
Controller 负责设置初始状态
和参数化$scope方法
用以控制行为。需要指出的 controller 并不保存状态也不和远程服务互动。
View 是 AngularJS 解析后渲染和绑定后生成的 HTML。这个部分帮助你创建 web 应用的架构。$scope 拥有一个针对数据的参考,controller 定义行为,view 处理布局和互动。
7. 使用 MVVM 模式有几大好处:
-
低耦合:View 可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
-
可重用性:可以把一些视图的逻辑放在 ViewModel 里面,让很多 View 重用这段视图逻辑。
-
独立开发:开发人员可以专注与业务逻辑和数据的开发 (ViewModel)。设计人员可以专注于界面 (View) 的设计。
-
可测试性:可以针对 ViewModel 来对界面 (View) 进行测试。
Android -------- MVC,MVP 和 MVVM 架构设计模式
MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用。它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 MVVM 架构的区别就不容易了。
一、MVC
MVC模式的意思是,软件可以分成三个部分。
- 视图(View):用户界面。
- 控制器(Controller):业务逻辑
- 模型(Model):数据保存
各部分之间的通信方式如下。
- View 传送指令到 Controller
- Controller 完成业务逻辑后,要求 Model 改变状态
- Model 将新的数据发送到 View,用户得到反馈
所有通信都是单向的。
MVC优点:
- 耦合性低
- 重用性高
- 生命周期成本低
- 部署快
- 可维护性高
- 有利软件工程化管理
MVC缺点:
- 没有明确的定义
- 不适合小型,中等规模的应用程序
- 增加系统结构和实现的复杂性
- 视图与控制器间的过于紧密的连接
- 视图对模型数据的低效率访问
- 一般高级的界面工具或构造器不支持模式
在MVC里,View是可以直接访问Model的。从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。
所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的
二、MVP
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。
1. 各部分之间的通信,都是双向的。
2. View 与 Model 不发生联系,都通过 Presenter 传递。
3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
MVP优点:
- 模型与视图完全分离,我们可以修改视图而不影响模型
- 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
- 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁
- 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)
MVP缺点:
由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责视图。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller
三、MVVM
MVVM是Model-View-ViewModel的简写,这个模式提供对View和View Model的双向数据绑定,使得View Model的状态改变可以自动传递给View
- Model:数据层,负责处理数据的加载或者存储
- View:视图层,负责界面数据的展示,与用户进行交互
- ViewModel:负责完成View于Model间的交互,负责业务逻辑
来自: http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
Android MVP,MVVM
一:先说 MVC:原文连接:http://blog.csdn.net/feiduclear_up/article/details/46363207
- M 层:适合做一些业务逻辑处理,比如数据库存取操作,网络操作,复杂的算法,耗时的任务等都在 model 层处理。
- V 层:应用层中处理数据显示的部分,XML 布局可以视为 V 层,显示 Model 层的数据结果。
- C 层:在 Android 中,Activity 处理用户交互问题,因此可以认为 Activity 是控制器,Activity 读取 V 视图层的数据(eg. 读取当前 EditText 控件的数据),控制用户输入(eg.EditText 控件数据的输入),并向 Model 发送数据请求(eg. 发起网络请求等)。
二、再说 MVP:原文连接:http://www.jianshu.com/p/b507a4dbe3ca
-
Presenter 中同时持有 View 以及 Model 的 Interface 引用,而 View 持有 Presenter 的实例。
-
当某个 View 需要展示某些数据时,首先会调用 Presenter 的某个接口,然后 Presenter 会调用 Model 请求数据。
-
当 Model 数据加载成功后会调用 Presenter 的回调方法通知 Presenter 数据加载完毕,最后 Presenter 再调用 View 层接口展示加载后数据。
不太爱用 mvp。mvp 无非就是面向接口编程的一个典型。presenter 通过 view 和 model 接口的引用,来调用具体实现类实现的方法,这么做的好处是,业务结构清晰,且将来更换实现类超级方便,因为业务结构不用改,就只是实现类摘掉,再换一个就是。虽然明知好处,但还是不太爱用~
最后:
采用哪种软件设计模式都是为了达到如下目的:
易于维护
易于测试
松耦合度
复用性高
健壮稳定
三、MVVM:
原文连接:http://blog.csdn.net/johnny901114/article/details/50706329
MVVM 是 Model-View-ViewModel 的简写。它是有三个部分组成:Model、View、ViewModel。
Model:数据模型层。包含业务逻辑和校验逻辑。
View:屏幕上显示的 UI 界面(layout、views)。
ViewModel:View 和 Model 之间的链接桥梁,处理视图逻辑。
MVVM 架构图如下:
MVVM 架构通过 ViewModel 隔离了 UI 层和业务逻辑层,降低程序的耦合度。通过 DataBinding 实现 View 和 ViewModel 之间的绑定。
Android App 中 MVC 的不足
一般来说,我们开发 Android App 是基于 MVC,由于 MVC 的普及和快速开发的特点,一个 app 从 0 开发一般都是基于 MVC 的。
Activity、Fragment 相当于 C (Controller), 布局相当于 V(View), 数据层相当于 M(Model)
松耦合具体带来的好处是:
随着业务的增长,Controller 里的代码会越来越臃肿,因为它不只要负责业务逻辑,还要控制 View 的展示。也就是说 Activity、Fragment 杂糅了 Controller 和 View,耦合变大。并不能算作真正意义上的 MVC。
编写代码基本的过程是这样的,在 Activity、Fragment 中初始化 Views,然后拉取数据,成功后把数据填充到 View 里。
假如有如下场景
:
我们基于 MVC 开发完第一版本,然后企业需要迭代 2.0 版本,并且 UI 界面变化比较大,业务变动较小,怎么办呢?
当 2.0 的所有东西都已经评审过后。这个时候,新建布局,然后开始按照新的效果图,进行 UI 布局。然后还要新建 Activity、Fragment 把相关逻辑和数据填充到新的 View 上。
如果业务逻辑比较复杂,需要从 Activity、Fragment 中提取上个版本的所有逻辑,这个时候自己可能就要晕倒了,因为一个复杂的业务,一个 Activity 几千行代码也是很常见的。千辛万苦做完提取完,可能还会出现很多 bug。
MVP 架构图如下:
MVP 把视图层抽象到 View 接口,逻辑层抽象到 Presenter 接口,提到了代码的可读性。降低了视图逻辑和业务逻辑的耦合。
但是有 MVP 的不足:
- 接口过多,一定程度影响了编码效率。其实这也不算是不足,为了更好的分层解耦,这也是必须的。
- 导致 Presenter 的代码量过大。
这个时候 MVVM 就闪亮登场了。从上面的 MVVM 功能图我们知道:
- 可重用性。你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 view 重用这段视图逻辑。
在 Android 中,布局里可以进行一个视图逻辑,并且 Model 发生变化,View 也随着发生变化。 - 低耦合。以前 Activity、Fragment 中需要把数据填充到 View,还要进行一些视图逻辑。现在这些都可在布局中完成(具体代码请看后面)
甚至都不需要再 Activity、Fragment 去 findViewById。这时候 Activity、Fragment 只需要做好的逻辑处理就可以了。
现在我们回到上面从 app1.0 到 app2.0 迭代的问题,如果用 MVVM 去实现那就比较简单,这个时候不需要动 Activity、Fragment,
只需要把布局按照 2.0 版本的效果实现一遍即可。因为视图逻辑和数据填充已经在布局里了,这就是上面提到的可重用性。
4.1. The view
A view component in MVP contains a visual part of the application.
The view binds to observable variables and actions exposed by the view model typically using the data binding framework.
The view is responsible for handling for example:
-
Menus
-
Permissions
-
Event listeners
-
Showing dialogs, Toasts, Snackbars
-
Working with Android
View
andWidget
-
Starting activities
-
All functionality which is related to the Android
Context
4.2. The view model
The view model contains the data required for the view. It is an abstraction of the view and exposes public properties and commands. It uses observable data to notify the view about changes. It also allows to pass events to the model. It is also a value converter from the raw model data to presentation-friendly properties)
The view model has the following responsibilities:
-
Exposing data
-
Exposing state (progress, offline, empty, error, etc)
-
Handling visibility
-
Input validation
-
Executing calls to the model
-
Executing methods in the view
The view model should only know about the application context. the application context can:
-
Start a service
-
Bind to a service
-
Send a broadcast
-
Register a broadcast receiver
-
Load resource values
It cannot:
-
Show a dialog
-
Start an activity
-
Inflate a layout
4.3. The model
Contains a data provider and the code to fetch and update the data. The data can be retrieved from different sources, for example:
-
REST API
-
Realm db
-
SQLite db
-
Handles broadcast
-
Shared Preferences
-
Firebase
-
etc.
Basically the same as the model in the MVP.
四、MVVM BroadcastReceiver
I have a class the Boolean field gets updated with a In my Meaning - having sort of a "listener" to changes of the I know there are tons of ways to do it, from broadcasting an What I am really looking for is sort of data binding with a converter, like you would do in a MVVM project. Is there such a thing in android? |
1 Answer
|
I assume you know about android data binding and you''re just asking how to do it for this specific case. If not, here is the android data binding guide. You will need a way to observe the boolean value so the UI can remain updated. The easiest way is to make it an ObservableBoolean field of your model object: When you create the binding, you must also assign the model: And when you receive the broadcast, you update the model: And your layout would be something like this: You could also avoid the model class if you keep track of the binding and set the variable directly on it. In that case, you''d have a variable: And your broadcast receiver would set the value:
|
Android MVVM 简单配置 --data Binding Library
MVVM:Model - 代表你的基本业务逻辑 View - 显示的内容 ViewModel-- 将 Model 和 View 联系起来的对象
想要使用这种模式开发 android 程序可以使用 Google 提供的一种方式 data Binding Library
最低要求:API level7 Gradle 15.0
在 android6.0 的 API 中如图:
第一步:在 build.gradle (Module:app) 中添加 dataBinding,然后点击右上角的同步
android {
dataBinding{
enabled=true;
}
}
启用 dataBinding
第二步:创建一个 JAVA BEAN 对象 本例以 User (userName,password) 对象为例
public class User {
public String userName;
public String password;
}
修饰符是 public 不需要 getter,setter 方法
再创建一个 Event 对象 UserEvent.java
这样就可以将 user 对页面上的控件的值进行对应,修改控件的值会自己修改 user 对象的值,反之亦然
public class UserEvent {
private User user;
//构造函数,将user传进来
public UserEvent(User user) {
this.user = user;
}
//对userName的监听
public TextWatcher userNameWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
//将改变后的值给user对象
user.userName = s.toString();
}
};
//对password的监听
public TextWatcher passwordWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
//将改变后的值给user对象
user.password=s.toString();
}
};
}
创建一个事件的监听对象 MyHandler.java
public class MyHandler {
private User user;
private Activity context;
private ProgressDialog pd;
//构造传参
public MyHandler(User user,Activity context,ProgressDialog pd){
this.user=user;
this.context=context;
this.pd=pd;
}
//登录事件
public void onClickLoginUser(View v){
if(TextUtils.isEmpty(user.userName) || TextUtils.isEmpty(user.password)){
showToast("用户名或密码为空");
}else{
pd.show();
new Thread(new Runnable() {
@Override
public void run() {
//判断是否登录成功
UserLoginNet net=new UserLoginNet();
if(net.sendUserInfo(user)){
showToast("欢迎回来:"+user.userName);
}else{
showToast("用户名或密码错误");
}
}
}).start();
}
}
private void showToast(final String content){
context.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context,content,Toast.LENGTH_SHORT).show();
pd.dismiss();
}
});
}
}
第三步:在布局文件最外层添加
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="event"
type="com.example.yangzhi.mvvm.UserEvent"></variable>
<variable
name="handler"
type="com.example.yangzhi.mvvm.MyHandler"></variable>
</data>
</layout>
将原布局文件的 xmlns: android = "http://schemas.android.com/apk/res/android"
放到现在的 <layout> 中
然后在控件的属性中添加: addTextChangedListener 需要自己输入,我试了一下没有提示,也不需要 android:text 属性
addTextChangedListener="@{event.userNameWatcher}"
整体代码
<EditText
addTextChangedListener="@{event.userNameWatcher}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
<EditText
addTextChangedListener="@{event.passwordWatcher}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{handler.onClickLoginUser}"
android:text="登录" />
button 的设置点击事件得注意一下,可别忘了
其它布局不变
第四步: 在 MainActivity.java 的 onCreate 方法中的配置
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
//这个就不再需要
//setContentView(R.layout.activity_main);
user = new User();
UserEvent event = new UserEvent(user);
binding.setEvent(event);
ProgressDialog pd=new ProgressDialog(this);
MyHandler myHandler=new MyHandler(user,this,pd);
binding.setHandler(myHandler);
整体代码,其实就上述代码:
public class MainActivity extends AppCompatActivity {
private User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
//这个就不再需要
//setContentView(R.layout.activity_main);
user = new User();
UserEvent event = new UserEvent(user);
binding.setEvent(event);
ProgressDialog pd=new ProgressDialog(this);
MyHandler myHandler=new MyHandler(user,this,pd);
binding.setHandler(myHandler);
}
}
整个 activity 的代码就上面那一点,其它的操作都放到其它文件中去了,不管是与控件相关的还是联网操作的都在其它文件
关于利用 JavaScript 数据绑定实现一个简单的 MVVM 库和js怎么绑定数据的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于5.MVVM 模式、Android -------- MVC,MVP 和 MVVM 架构设计模式、Android MVP,MVVM、Android MVVM 简单配置 --data Binding Library等相关知识的信息别忘了在本站进行查找喔。
本文标签: