移动架构-MVVM框架
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开
MVVM的优点
可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。 在Android中,布局里可以进行一个视图逻辑,并且Model发生变化,View也随着发生变化
低耦合:以前Activity、Fragment中需要把数据填充到View,还要进行一些视图逻辑。现在这些都可在布局中完成,甚至都不需要再Activity、Fragment去findViewById。这时候Activity、Fragment只需要做好的逻辑处理就可以了
MVVM
角色
View: 对应于Activity和XML,负责View的绘制以及与用户交互
Model: 实体模型
ViewModel: 负责完成View与Model间的交互,负责业务逻辑
数据驱动
在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多
MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具
DataBinding支持的表达式
- 数学表达式:
+ - / * %
- 字符串拼接:
+
- 逻辑表达式:
&& ||
- 位操作符:
& | ^
- 一元操作符:
+ - ! ~
- 位移操作符:
>> >>> <<
- 比较操作符:
== > < >= <=
instanceof
- 分组操作符:
()
- 字面量:
character, String, numeric, null
- 强转、方法调用
- 数组访问:
[]
- 三元操作符:
?:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
支持dimen
,还支持color
、string
、drawable
、anim
等 - 聚合判断(
Null Coalescing Operator
)语法??
android:text="@{user.userName ?? user.realName}"
意思是如果userName为null
,则显示realName
- 字符拼接
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`username is :`+user.username}"/>
这里的字符拼接不是用单引号哦,用的是ESC按键下面那个按键按出来的。目前DataBinding中的字符拼接还不支持中文
官方手册:https://developer.android.com/tools/data-binding/guide.html
MVVM用法
模板写法
<layout xmlns:android="http://schemas.android.com/apk/res/android" >
<data>
<!--此处定义该布局要用到的数据的名称及类型-->
</data>
<!--此处按照常规方式定义要使用的布局,其中可以使用binding表达式代表属性值,所谓binding表达式,指形如"@{user.firstName}"的表达式-->
</layout>
自定义Binding类名(Custom Binding Class Names)
- 以为根节点布局,
android studio
默认会自动产生一个Binding类。类名为根据布局名产生,如一个名为activity_simple
的布局,它的Binding类为ActivitySimpleBinding
,所在包为app_package/databinding
- 也可以自定义Binding类的名称和包名
<data class="CustomBinding"></data> 在app_package/databinding下生成CustomBinding
<data class=".CustomBinding"></data> 在app_package下生成CustomBinding
<data class="com.example.CustomBinding"></data> 明确指定包名和类名
Layout布局中Includes 标签使用
<include layout="@layout/name"
bind:user="@{user}"/>
BaseObservable的方式
使User继承BaseObservable
,在get方法上加上注解@Bindable
,会在BR(BR类自动生成的)生成该字段标识(int)
set方法里notifyPropertyChanged(BR.field);
@Bindable
public String getUserName() {
return userName;
}
理解实例
在项目gradle的android标签下中添加
dataBinding{
enabled true
}
编写测试类
public class User {
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
编写布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!--第一种引入方式-->
<variable
name="user"
type="com.cj5785.mvvmdesign.User" />
<!--第二种引入方式-->
<!--<import type="com.cj5785.mvvmdesign.User" />-->
<!--<variable-->
<!--name="user"-->
<!--type="User" />-->
<!--如果有多个相同model,可以取别名-->
<!--<import alias="typeUser" type="com.cj5785.mvvmdesign.User" />-->
<!--<variable name="user" type="typeUser" />-->
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{user.name}" /><!--显示字段-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{user.password}" /><!--显示字段-->
</LinearLayout>
</layout>
在Activity中调用测试
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用MVVM时候,这里不能使用setContentView
// setContentView(R.layout.activity_main);
//ActivityMainBinding在编译时自动生成
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("jack","123456");
binding.setUser(user);
}
}
这样就完成了MVVM模型最简单的运用
此时就显示出了设置的name和password
接下来测试数据变化更新UI
修改测试类
public class User extends BaseObservable{
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
notifyPropertyChanged(BR.password);
}
}
在Activity中使用延迟设置
public class MainActivity extends AppCompatActivity {
User user;
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用MVVM时候,这里不能使用setContentView
// setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
user = new User("jack", "123456");
binding.setUser(user);
handler.postDelayed(new Runnable() {
@Override
public void run() {
user.setName("Bob");
user.setPassword("654321");
}
}, 5000);
}
}
然后可以看到在经历5秒以后,文字被改变了
使用MVVM框架加载网络图片又怎么做呢
首先导入com.squareup.picasso:picasso
依赖
在User中添加相应的图片获取方法
public class User extends BaseObservable{
private String name;
private String password;
private String header;
public User(String name, String password,String header) {
this.name = name;
this.password = password;
this.header = header;
}
@BindingAdapter("bind:header")
public static void getImage(ImageView imageView,String url){
Picasso.with(imageView.getContext()).load(url).into(imageView);
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
notifyPropertyChanged(BR.password);
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
}
修改布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<!--第一种引入方式-->
<variable
name="user"
type="com.cj5785.mvvmdesign.User" />
<!--第二种引入方式-->
<!--<import type="com.cj5785.mvvmdesign.User" />-->
<!--<variable-->
<!--name="user"-->
<!--type="User" />-->
<!--如果有多个相同model,可以取别名-->
<!--<import alias="typeUser" type="com.cj5785.mvvmdesign.User" />-->
<!--<variable name="user" type="typeUser" />-->
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:header="@{user.header}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{user.name}" /><!--显示字段-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{user.password}" /><!--显示字段-->
</LinearLayout>
</layout>
在Activity中直接调用
public class MainActivity extends AppCompatActivity {
User user;
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用MVVM时候,这里不能使用setContentView
// setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
user = new User("jack", "123456","http://i0.hdslb.com/bfs/archive/42172b20c899bcbbad0d46868af81b8081e999f1.jpg");
binding.setUser(user);
handler.postDelayed(new Runnable() {
@Override
public void run() {
user.setName("Bob");
user.setPassword("654321");
}
}, 5000);
}
}
接下来看看除了使用BaseObservable的另一种方式
public class UserField {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> password = new ObservableField<>();
}
布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="field"
type="com.cj5785.mvvmdesign.UserField"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{field.name}" /><!--显示字段-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:text="@{field.password}" /><!--显示字段-->
</LinearLayout>
</layout>
调用
public class FieldTestActivity extends Activity {
UserField userField = new UserField();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setField(userField);
userField.name.set("Alen");
userField.password.set("121212");
}
}
移动架构-MVVM框架的更多相关文章
- iOS应用千万级架构:MVVM框架
业务模块内的MVC和MVVM架构 目前,唯品会中MVC和MVVM架构并存,后期会偏重于MVVM架构的使用. MVC架构 Model:程序中要操纵的实际对象的抽象,为Controller提供经过抽象的业 ...
- js架构设计模式——前端MVVM框架设计及实现(二)
前端MVVM框架设计及实现(二) 在前端MVVM框架设计及实现(一)中有一个博友提出一个看法: “html中使用mvvm徒增开发成本” 我想这位朋友要表达的意思应该是HTML定义了大量的语法标记,HT ...
- js架构设计模式——前端MVVM框架设计及实现(一)
前端MVVM框架设计及实现(一) 最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的avalon开始了,我 ...
- “老坛泡新菜”:SOD MVVM框架,让WinForms焕发新春
火热的MVVM框架 最近几年最热门的技术之一就是前端技术了,各种前端框架,前端标准和前端设计风格层出不穷,而在众多前端框架中具有MVC,MVVM功能的框架成为耀眼新星,比如GitHub关注度很高的Vu ...
- 迷你MVVM框架 avalonjs 入门教程
新官网 请不要无视这里,这里都是链接,可以点的 OniUI组件库 学习教程 视频教程: 地址1 地址2 关于AvalonJs 开始的例子 扫描 视图模型 数据模型 绑定 作用域绑定(ms-contro ...
- 迷你MVVM框架 avalonjs1.5 入门教程
avalon经过几年以后,已成为国内一个举足轻重的框架.它提供了多种不同的版本,满足不同人群的需要.比如avalon.js支持IE6等老旧浏览器,让许多靠政府项目或对兼容性要求够高的公司也能享受MVV ...
- JavaScript富应用MVC MVVM框架
对框架的挑选 Ember.js.Backbone.js.Knockout.js.Spine.js.Batman.js , Angular.js 1. 轻量级的应用选择哪一个会比较好?2. 那一个比较简 ...
- vue.js学习笔记(一):什么是mvvm框架,vue.js的核心思想
一:MVVM框架 MVVM框架的应用场景: 1.针对具有复杂交互逻辑的前端应用 2.提供基础的架构抽象 3.提供ajax数据持久化,保证前端用户体验 二:vue.js的核心思想 (一):数据驱动 ( ...
- MVVM框架avalon在兼容旧式IE
迷你MVVM框架avalon在兼容旧式IE做的努力 当前标签: avalon 共3页: 1 2 3 下一页 迷你MVVM框架avalon在兼容旧式IE做的努力 司徒正美 2014-03-13 11: ...
随机推荐
- document基本操作 动态脚本-动态样式-创建表格
var html = document.documentElement; var body = document.body; window.onload = function() { //docume ...
- Hello 2019题解
Hello 2019题解 题解 CF1097A [Gennady and a Card Game] map大法好qwq 枚举每一个的第\(1,2\)位判是否与给定的重复即可 # include < ...
- Linux使用Aria2命令下载BT种子/磁力/直链文件 转载
Linux使用Aria2命令下载BT种子/磁力/直链文件 博主: Rat's 发布时间:2017 年 10 月 10 日 26725 次浏览 8 条评论 1073 字数 分类:主机教程 首页 正文 分 ...
- 2019暑期金华集训 Day1 数据结构
自闭集训 Day1 数据结构 CF643G 用类似于下面的方法,搬到线段树上. 如何合并两个集合?先全部放在一起,每次删掉最小的\(cnt_i\),然后把其他所有的\(cnt\)都减去\(cnt_i\ ...
- 如何实现一个 windows 桌面动态壁纸
更新: 2018/08/31 WS_MOUSE_LL 钩子,实现底层壁纸交互效果. 一.介绍 国内玩家第一次看到动态壁纸,都是出于一款来自 Wallpaper Engine 的 Steam 程序. ...
- python下pip 安装 pyautogui报错Command "python setup.py egg_info" failed with error code 1 in C:\Users\Administrator\AppData\Local\Temp\pip-install-svhtepho\pygetwindow\
python装的3.6 64位,使用命令pip install pyautogui 或者pip install -U pyautogui 都失败了 报错如下: Command "python ...
- 【HDU4622】Reincarnation
[HDU4622]Reincarnation 一眼似乎不可做,但发现\(strlen(x)\)很小,暴力\(O(n^2)\)预处理每个区间\((l,r)\),查询时\(O(1)\)输出就好了 #inc ...
- ansible 任务流程控制
一.任务委托 默认情况下,ansible的所有任务都是在指定的机器上运行的,当在一个独立的群集环境中配置时,但是只想操作其中的某一台主机,或者在特定的主机上运行,此时就需要用到ansible的任务委托 ...
- Java的反射是什么?有什么用?
首先我要简单的来说一下什么是Java的反射机制: 在Java里面一个类有两种状态--编译和运行状态,通常我们需要获取这个类的信息都是在编译阶段获得的,也就是直接点出来或者new出来,可是如果需要在类运 ...
- 在IntelliJ IDEA中启动tomcat出现Can't load AMD 64-bit .dll on a IA 32-bit' platform问题详解
第一查看jdk版本 第二查看IntelliJ IDEA中运行tomcat的配置的jdk 比较两个jdk版本是否一致.或者查看tomcat是64还是32位的