概述
Model :基本业务逻辑
View :视图内容
ViewModel: 将前面两者联系在一起的对象
作用
它通过双向绑定(松耦合)解决了Model与View联系比较紧密的问题。
mvvm的双向绑定有一定的局限性,后面会仔细讲到。
配置
android 官方早在Android Studio 1.3、Android Gradle插件1.5之后默认添加了,只需要在项目的build.gradle中配置:
android{
...
dataBinding{
enabled true
}
}
如果你的as和gradle插件版本低于上述版本则需要则需要如下操作:
Project 的 build.gradle中添加:classpath ‘com.android.databinding:dataBinder:1.0-rc0’
app 的 build.gradle中添加:apply plugin: ‘com.android.databinding’
Project 的 build.gradle中:
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.android.databinding:dataBinder:1.0-rc0'
}
}
app 的 build.gradle中:
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
基本使用
1,布局文件。mvvm模式开发布局文件不再是以布局开头了,而是以< layout >开头
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!--使用import来导入需要用的包-->
<import type="com.lh.mvvm.bean.UserBean" />
<!--使用alias来给包设置别名,用于区别不同包路径下的同名类-->
<import
alias="mUtils"
type="com.lh.mvvm.utils.MvvmUtils" />
<import type="java.util.ArrayList" />
<import type="android.databinding.ObservableArrayList" />
<!--使用关键字variable来声明一个变量,name为变量名,type为指向的对象,可以是类名也可以是类名的别名-->
<variable
name="user"
type="UserBean" />
<!--泛型的支持会在编译时期报红线,<>需要通过转义字符才行,<数据类型> -->
<variable
name="list"
type="ArrayList<UserBean>" />
<!--对于基本类型,可以像java代码一样不用去导入包,直接使用-->
<variable
name="postion"
type="int" />
<!-- <!–Observable数据改变自动更新,用于数据和view的双向绑定–>
<variable
name="list1"
type="ObservableArrayList<UserBean>" />
-->
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--使用变量-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.userName}" />
<!--使用自定义方法-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mUtils.capitalize(user.userName)}" />
<!--android:text="@{user.userName != null ? user.userName : user.userAge}"
等价于
android:text="@{user.userName ?? user.userAge}"
-->
<!--这里不是单引号,是中文字符~符号按出来的,位于Esc按键的下方-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.userName != null ? user.userName : user.userAge + ``}" />
<!--这里最外层使用单引号,里面需要将其他类型转成字符串的时候,用双引号-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{user.userName ?? user.userAge + ""}' />
<!--使用资源变量,如果不强转会报错,一般报错信息指明了报错原因-->
<!--这里的android:visibility="@{user.userId == 1 ? View.GONE : View.VISIBLE}会报错,我们直接用代码所指向的值,一样起作用-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@{user.userId==1? (int)@dimen/padding_x : (int)@dimen/padding_xx}"
android:text="@{@string/app_name +`我擦泪`}"
android:visibility="@{user.userId == 1 ? 0x00000000 : 0x00000008}" />
<!--获取集合中数据的方式-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{list.get(postion).userName}" />
<!--List集合既可以和数组一样通过索引获取值list[index]方式,也可以调用API-->
<Button
android:id="@+id/btn_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{list[postion].userName}" />
</LinearLayout>
</layout>
2,Activity写法
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
ActivityMainBinding activityMainBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//它的名字取决于你的layout文件名,activity_main
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
//初始化数据
UserBean userBean1 = new UserBean(1, "aaa", 1, 1);
UserBean userBean2 = new UserBean(2, "bbb", 2, 4);
UserBean userBean3 = new UserBean(3, "ccc", 3, 15);
ArrayList<UserBean> data = new ArrayList<>();
data.add(userBean1);
data.add(userBean2);
data.add(userBean3);
//这里的方法和xml中定义的方法相对应
//赋值过后,控件会自动填充数据
activityMainBinding.setUser(userBean1);
activityMainBinding.setList(data);
//有id的控件也可以通过databinding得到
activityMainBinding.btnTest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.equals(activityMainBinding.btnTest)){
//修改databinding中的数据
activityMainBinding.getList().get(0).setUserName("bbb");
//每一个定义的变量都有相对应的get/set方法activityMainBinding.btnTest.setText(activityMainBinding.getList().get(0).getUserName());
}
}
}
基本使用就是这样的,下面看看进阶使用
数据的双向绑定 Observable
再定义一个UserBean
public class UserBean {
public ObservableInt userId = new ObservableInt();
public ObservableField<String> userName = new ObservableField<>();
public ObservableDouble userAge = new ObservableDouble();
public ObservableFloat userSex = new ObservableFloat();
}
增加main_layout.xml中的代码:
<!--使用alias来给包设置别名,用于区别不同包路径下的同名类-->
<import
alias="observableUserBean"
type="com.lh.mvvm.observable.UserBean" />
<!--双向绑定数据的对象-->
<variable
name="observableuser"
type="observableUserBean" />
<!--双向绑定,当前observableuserbean 下面的数据是双向绑定的,只要数据改变,view中的数据也会跟着改变-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`双向绑定数据,姓名:`+ observableuser.userName}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`双向绑定数据,年龄:`+ observableuser.userAge}" />
activity新增代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
com.lh.mvvm.observable.UserBean ouserBean1 = new com.lh.mvvm.observable.UserBean();
ouserBean1.userId.set(1);
ouserBean1.userName.set("oaaa");
ouserBean1.userAge.set(1d);
ouserBean1.userSex.set(1f);
activityMainBinding.setObservableuser(ouserBean1);
activityMainBinding.btnTest1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.equals(activityMainBinding.btnTest)) {
//修改databinding中的数据
activityMainBinding.getList().get(0).setUserName("bbb");
//每一个定义的变量都有相对应的get/set方法
activityMainBinding.btnTest.setText(activityMainBinding.getList().get(0).getUserName());
} else if (v.equals(activityMainBinding.btnTest1)) {
//双向绑定数据不需要重新调用控件,数据改变,相对应绑定数据的view也会改变
activityMainBinding.getObservableuser().userName.set("动态修改后的数据,view自动刷新数据");
activityMainBinding.getObservableuser().userAge.set(100000);
}
}
动态修改数据主要用到了databinding中的Observable对象