简介
在开发中可能你使用过MVP
设计模式来对代码进行解耦,但是谷歌发布的DataBinding
库更加简化了我们的代码,同时也催生了MVVM
设计模式在Android
中的使用。在MVP
模式中我们需要Model
、View
、Presenter
三者进行配合使用,而MVVM
模式是由Model
、View
、ViewModel
进行配合的,其中的区别主要在于ViewModel
。DataBinding
是一个实现数据和UI
绑定的框架,是构建MVVM
模式的一个关键的工具,其奇妙之处在于可以将XML
文件与指定的JAVA
类绑定,实现数据的自动更新效果。
MVVM
是MVP
的演进版本,其核心是实现了双向绑定,主要依赖于Android
提供的DataBinding
兼容库实现。在MVVM
中将MVP
中Presenter
替换为ViewModel
,而ViewModel
相当于UI
与Model
的桥梁,将View
与Model
直接绑定并将相关的业务逻辑下移于Model
层中进行处理。
Model
:负责数据实现和逻辑处理。
View
:对应于Activity
和xml
,负责View
的绘制以及与用户交互。
ViewModel
:创建关联,将Model
和View
绑定起来,如此之后Model
更改后通过ViewModel
反馈给View
。View
的xml
布局文件经过特定的编写及编译工具处理后,生成的代码会接收ViewModel
的数据通知消息,自动刷新界面。
单向绑定中数据的流向是单方面的,只能从代码流向UI
,而双向绑定的数据流向是双向的,当业务代码中的数据改变时,UI
上的数据能够得到刷新,当用户通过UI
交互编辑了数据时,数据的变化也能自动的更新到业务代码中的数据上。对于双向绑定可以使用DataBinding
,它是一个实现数据和UI绑定的框架,是构建MVVM
模式的一个关键的工具。
基本用法
1、环境要求
1、Android Studio
版本在1.3
以上;
2、gradle
的版本要在1.5.0-alpha1
以上;
3、需要在Android SDK Manager
中下载Android Support Repository
;
4、在对应Module
的build.gradle
中添加:
android {
......
dataBinding {
enabled = true
}
......
}
2、创建实体类
public class User {
private String userName;
private String nickName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
3、XML布局
布局文件不再是以传统的某一个容器作为根节点,而是使用<layout></layout>
作为根节点,在<layout>
节点中我们可以通过<data>
节点来引入我们要使用的数据源。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.wiggins.mvvm.bean.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/theme_bg"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="@{user.userName}"
android:textColor="@color/blue"
android:textSize="@dimen/font_normal" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="@{user.nickName}"
android:textColor="@color/blue"
android:textSize="@dimen/font_normal" />
</LinearLayout>
</layout>
4、定义variable
在<data>
节点中定义的variable
节点,其中name
属性表示变量的名称,type
属性表示这个变量的类型,实例就是我们实体类的具体位置,当然data
节点也支持import
,所以上面的代码也可以换一种形式来写。
<data>
<import type="com.wiggins.mvvm.bean.User" />
<variable
name="user"
type="User" />
</data>
使用import
节点将User
导入,然后直接使用即可。
然后我们前面在build.gradle
中添加的dataBinding
会根据xml
文件的名称Generate
一个继承自ViewDataBinding
的类。
例如:这里xml
的文件名叫activity_main.xml
,那么生成的类就是ActivityMainBinding
。
注意:
java.lang.*
包中的类会被自动导入,可以直接使用,例如要定义一个String
类型的变量:
<variable
name="name"
type="String" />
5、绑定variable
修改Activity
的onCreate
方法,用DataBindingUtil.setContentView()
来替换掉以前的setContentView()
,然后使用之前创建的User
对象,通过binding.setUser(user)
与variable
进行绑定。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User();
user.setUserName("小明");
user.setNickName("一花一世界");
binding.setUser(user);
}
其中的ActivityMainBinding
类是DataBinding
框架为我们自动生成的,它与你的XML
文件名字相关。比如我的XML
文件名字是activity_main
,那么生成的类就会取消下划线并且在最后加上Binding
就得到了ActivityMainBinding
。这个类的实例可以通过DataBindingUtil.setContentView()
来得到,同时此类里面有我们XML
文件里所有的控件信息,因此也不需要去findViewById
了,界面上的管理基本可以全部转移到绑定的ViewModel
中了,可以参考以下方式对相应的控件进行操作。
binding.tvContent.getText().toString().trim();
注意:
ActivityMainBinding
类是自动生成的,所有的set
方法也是根据variable
名称生成的。例如我们定义了以下两个变量:
<data>
<variable name="userName" type="String" />
<variable name="nickName" type="String" />
</data>
那么就会生成对应的两个set
方法。
setUserName(String userName);
setNickName(String nickName);
6、使用variable
数据与variable
绑定之后,xml
的UI
元素就可以直接使用了。
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="@{user.nickName}"
android:textColor="@color/blue"
android:textSize="@dimen/font_normal" />
在布局文件中,TextView
的text
属性设置成了@{user.nickName}
,这样该TextView
就会直接将User
实体类的nickName
属性值显示出来了。
基本运算
1、三目运算
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{user.userName??user.nickName}"
android:textColor="@color/blue"
android:textSize="@dimen/font_normal" />
两个??
表示如果userName
为null
则显示nickName
,否则显示userName
。
2、字符拼接
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{
`userName is : `+user.userName}"
android:textColor=