知是行之始,行是知之成。
文章配套的 Demo:https://github.com/muyi-yang/DataBindingDemo
Demo 支持 Java 和 Kotlin 双语言,master 分支为 Java 语言代码,kotlin 分支为 Kotlin 语言代码。

DataBinding介绍

2015 年的 Google IO 大会上,Android 团队发布了一个数据绑定框架(Data Binding Library),它是为了解决数据和 UI 的绑定问题,同时也是对 MVVM 模型的一个实践和引领。MVVM 模型不了解的请自行补上。

优点

  • 在 XML中绑定数据,XML变成UI的唯一真实来源
  • 去掉 Activities & Fragments 内的大部分 UI 代码(setOnClickListener, setText, findViewById)
  • 数据变化可自动刷新 UI,同时保证 UI 操作都在主线程运行

缺点

  • IDE 支持还不完善,在 XML 中代码提示、表达式验证都有很大缺失
  • 有些报错信息不明显,初学者排错难度较大
  • 重构支持较差,数据绑定写在 XML 中,丧失面向对象特性

开启 DataBinding

Gradle 配置

想在你的应用程序中使用 Data Binding,需要在应用程序 module 中的 build.gradle 文件中添加 dataBinding 配置,此配置将会在你的项目里添加必要的 Data Binding 插件以及编译配置依赖。

android {....dataBinding {enabled = true    }
}

注意:你必须为依赖于使用 Data Binding 的库(aar)的应用程序在 gradle 中增加开启 Data Binding 的配置,即使这个 module 没有直接使用 Data Binding 也需要。
例如: A module 依赖 B module,B module 又依赖 C module,但只有 C module 中使用了 Data Binding ,这个时候 A B C 三个 module 都必须在 gradle 中增加以上配置,否则会在 Data Binding V1 编译器中编译不过,在 V2 编译器中可编译,但会运行时出错。

Android Gradle 插件在版本 3.1.0-alpha06 包含一个新的 Data Binding 编译器(V2),用于生成 Binding 类。它的主要改变有:

  1. 新的编译器是增量编译 Binding 类,这在大多数情况下加快了编译速度。
  2. library 模块的 Binding 类会被编译并打包到 AAR 文件中。 依赖这些库的应用程序不再需要重新生成 Binding 类。
  3. 老版本在编译出错时,经常会出现一些与真真错误不符合的提示,这个问题在新版本中已经做了修改。
  4. 绑定适配器(binding adapters)只影响自己 module 中的代码和 module 的使用者,它不能更改 module 依赖库中的适配器的行为。( 绑定适配器后面我们会详细讲解)

要启用新的 Data Binding 编译器,请在 gradle.properties 文件中添加以下选项:

android.databinding.enableV2=true

或者在 gradle 命令中通过添加以下参数来启用新的编译器:

-Pandroid.databinding.enableV2=true

但是这个编译器在 Android Studio 3.2 版本中已经是默认启用的状态,所以你如果是 Android Studio 3.2 版本及以上版本可以不用关心这个特征。

注明:Data Binding 提供了兼容,它可以支持 Android 4.0(API 14)及以上系统。Data Binding 插件需要 Android Studio 1.3.0 及以上版本,Gradle 1.5.0 及以上版本才能正常工作。
本文章及例子是基于 Android Studio 3.3.1版本,Gradle 4.10.1 版本。电脑系统是 Ubuntu 16.04(有些问题跟系统有关)。

XML写法

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_info"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>
</layout>

Data Binding 的布局文件有点不同的是:起始根标签是 layout,标签里面的内容和普通的布局没有区别。

Data Binding 插件会检索所有布局文件,会把根标签为 layout 的布局编译出一个继承自 ViewDataBinding 的类(build 目录下)。其命名规则是根据布局文件名来的,比如 activity_main.xml,那么生成的类就是 ActivityMainBinding。ActivityMainBinding 类是一个抽象类,它的实现类是 ActivityMainBindingImpl(也在build目录下),它的作用就是实现了 Data Binding 的一系列功能和特征。什么功能和特征?别急,后面会讲到!我们先看如何使用 Data Binding 布局。

布局使用

前面说了 Data Binding 的功能和特征在自动生成的 ActivityMainBinding 类中,那我们需要获取到 ActivityMainBinding 对象才能使用它。使用了 Data Binding 的布局在 Activity 中就不能直接调用 setContentView(R.layout.activity_main)设置布局了,你得这样做:

private ActivityMainBinding binding;@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}

在 Activity 中通过 DataBindingUtil 工具类的 setContentView 方法设置布局到 Activity 当中,同时返回
ActivityMainBinding 对象。有了 ActivityMainBinding 对象,我们就可以去体验 Data Binding 的魅力了。

如果你是在代码运行时创建View,想使用 Data Binding,你可以通过如下方式获取绑定类:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

如果你是在 Fragment、ListView 或者 RecyclerView 的适配器中使用 Data Binding,你可以使用
DataBindingUtil 类的 flatflate() 方法,如下面的代码示例所示:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//或者
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

使用绑定类中的 View

使用了 Data Binding 我们不在需要 findViewById() 获取对象了,因为 Data Binding 编译插件会检索布局文件中的控件,把已经声明了 ID 的 View 自动创建对象到 ActivityMainBinding 类中,直接获取使用即可。对象的命名规则是根据控件 ID 名来的,比如 android:id="@+id/tv_info",自动生成后的对象名为 tvInfo(去除下划线,并以驼峰格式命名):

private ActivityMainBinding binding;@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.activity_main);binding.tvInfo.setText("我是使用Data Binding的Demo");
}

以上是通过 ActivityMainBinding 对象获取布局中 TextView 的对象 tvInfo 并设置新值。

数据绑定

要进行数据绑定,首先要在布局中声明绑定变量,声明变量需要使用 data 标签以及 variable 标签。data 标签里面是用来做一些声明,比如声明变量,导入数据类型等。

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="com.example.databindingdemo.bean.UserInfo" /><variablename="user"type="UserInfo" /></data>.....
</layout>

这是一个用户信息界面的数据绑定,import 标签是导入一个数据类型,variable 标签是声明一个类型为 UserInfo 的变量 user

绑定属性

数据实体类:

public class UserInfo {public String name;public int age;public int sex;public String sign;
}

完整布局:

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="com.example.databindingdemo.bean.UserInfo" /><variablename="user"type="UserInfo" /></data><android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"android:text="@{@string/name(user.name), default=姓名}"android:textSize="18sp"app:layout_constraintLeft_toLeftOf="parent" /><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"android:text="@{@string/age(String.valueOf(user.age)), default=年龄}"android:textSize="18sp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_name" /><TextViewandroid:id="@+id/tv_sex"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"android:text="@{@string/sex(user.sex == 1?@string/sex_man:@string/sex_woman), default=性别}"android:textSize="18sp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_age" /><TextViewandroid:id="@+id/tv_sign"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"android:text="@{user.sign, default=个性签名}"android:textSize="18sp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_sex" /></android.support.constraint.ConstraintLayout>
</layout>

在 layout 中的表达式使用“@{}”语法在属性中编写,完整布局中有多个这样的表达式,比如为 TextView 设置值:

<TextViewandroid:id="@+id/tv_sign"...android:text="@{user.sign, default=个性签名}".../>

这里的“@{}”中的表达式是从 user 对象(前面声明的变量)中获取 sign 字段绑定到了 TextView 中,后面的 default 属性是用来设置布局预览时的值,它是可选字段,也可以直接写成 android:text="@{user.sign}",只不过这样写在布局预览时就不会显示内容。

以下为预览效果:

小插曲:本 Demo 一开始是基于 Ubuntu 系统写的,在 xml 中写中文是没问题的,但后来在 Win 系统上运行 Demo 则报 Caused by: org.apache.xerces.impl.io.MalformedByteSequenceException: Invalid byte 2 of 3-byte UTF-8 sequence. 错误,这是因为 Win 在编译中文时的编码问题(Demo 已修正)。在此提醒广大读者,不要偷懒,应该把所有中文都写到 string.xml 中去,在 xml 中这样引用android:text="@{@string/name(user.name), default=@string/default_name}",特别是在使用了 Data Binding 的情况下,这样会减少很多迷之编译错误。

绑定方法

前面讲了绑定对象的属性,还可以绑定对象的方法,比如:

public class UserInfo {private String name;...public String getName() {return name;}public void setName(String name) {this.name = name;}...
}

有很多时候我们的对象属性是私有的,我们提供了 Getter 和 Setter 方法,在绑定的时候我们可以这样写android:text="@{user.name}", 为什么不是android:text="@{user.getName()}"呢?这是因为 Data Binding 内部做了处理,它会把 getName() 方法解析为 name(),所以我们可以直接使用表达式 @{user.name}

注意:只要项目中开启了Data Binding功能,所有的 getxxx 方法都遵循这个规则。

对于类中的字段、 getter 方法和 ObservableField 对象都可以在表达式中使用格式引用:

android:text="@{user.name}"

在编译生成的绑定类中也会自动检查空值并避免空指针异常。 例如,在表达式 @{ user.name } 中,如果 usernull,则 user.name 的默认值为 null。 如果表达式 @{ user.age },其中 age 类型为 int,那么数据绑定使用默认值 0,其他数据类型类似。

设置数据

布局写好后,我们只需在代码中绑定对应数据即可:

private ActivityUserBinding binding;@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.activity_user);UserInfo info = new UserInfo();info.name = "木易";info.age = 28;info.sex = 1;info.sign = "问君能有几多愁,恰似一杯二锅头";binding.setUser(info);
}

以上是获取 ActivityUserBinding 对象,调用 setUser 方法绑定数据,setUser 方法是自动编译生成的,命名规则是根据布局中声明的变量 user 字段(<variable name="user" type="UserInfo" />)而定的,在布局中声明的所有变量都会自动生成 Getter 和 Setter 方法。当调用 setUser 方法时,会自动触发所有绑定了 UserInfo 对象的 View 重新赋值,当界面刷新时 UserInfo 中的信息就显示在界面上了。

至此 Data Binding 算是用上了,但仅仅只是打了个照面,好比能运行 “hello word” 了。这只是一个开始,接下来的几篇文章会比较详细的讲解 Data Binding 的功能和特性。

此篇到这里就结束了,可以查看下一篇 Data Binding 详解(二)-布局和绑定表达式。

如果你觉得文章有帮助到你,记得点个喜欢以表支持,同时欢迎你的指正和建议。十分感谢!

Data Binding 详解(一)-从零开始相关推荐

  1. java data使用_@Data注解详解及使用方法-Fun言

    @Data作用 去除Getter,Setter,equals,hashCode,toString方法,@Data注解在类上时,简化java代码编写,为该类提供读写属性.简单来说就是不用再手动添加get ...

  2. 一文搞定 Spring Data Redis 详解及实战

    转载自  一文搞定 Spring Data Redis 详解及实战 SDR - Spring Data Redis的简称. Spring Data Redis提供了从Spring应用程序轻松配置和访问 ...

  3. Ext.data.GroupingStore详解

    Ext.data.GroupingStore详解 Ext.data.GroupingStore 继承自Ext.data.Store,为Store增加了分组功能.其它用法与Store一致,惟一需要注意的 ...

  4. 【转载】salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解...

    salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解 建立好的数据表在数据库中查看有很多方式,本人目前采用以下两种方式查看数据表. 1.采用schema ...

  5. mysql的load data_【MySQL】load data语句详解(一)

    作者  罗小波 沃趣科技高级MySQL数据库工程师 load data语句详解 背景 数据库版本:MySQL 5.7.18 服务器信息:本地到处导入在10.10.30.241上演示,local远程导入 ...

  6. html css data-,HTML+CSS入门 HTML自定义data属性详解

    本篇教程介绍了HTML+CSS入门 HTML自定义data属性详解,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门.< 可以在HTML标签上添加任意以 "data-&q ...

  7. 25.消除不相关的细节/裂缝桥接(形态学 --膨胀与腐蚀详解 )--- OpenCV从零开始到图像(人脸 + 物体)识别系列

    本文作者:小嗷 微信公众号:aoxiaoji 吹比QQ群:736854977 简书链接:https://www.jianshu.com/u/45da1fbce7d0 本文你会找到以下问题的答案: 形态 ...

  8. Tensorflow数据预处理之tf.data.TFRecordDataset---TFRecords详解\TFRecords图像预处理

    目录 1.概述 2.预处理数据 2.1.常量定义 2.2.导入库 2.3.从train.txt文件中读取图片-标签对 2.4.预处理图片并保存 2.5.调用main函数 3.读取预处理后的数据 3.1 ...

  9. ajax jsonp 解析data,jsonp详解

    title: jsonp详解 tags: categories: ajax不允许跨域获取数据 说明,假定后端语言是 PHP script标签 jsonp的原理:script标签具有跨域性,可以利用Sc ...

  10. Android vector Path Data画图详解

    下面来解释一下"M 100,240 C510,300 80,100 300,160 H40 v80"这样字符串的意义.  分为四种情况来解释:  1. 移动指令:Move Comm ...

最新文章

  1. 腾讯AI开源框架Angel 3.0重磅发布:超50万行代码,支持3种算法,打造全栈机器学习平台...
  2. IoT和AI如何让企业在疫情期间重启业务
  3. U盘安装Linux CentOS 6.5 64位操作系统(来自互联网)
  4. easyUI的图标设置
  5. Android 插件化原理解析——Hook机制之AMSPMS
  6. levedb 导入 mysql_LevelDB-初始篇
  7. Flink 1.9 写入HDFS报错 UnsupportedFileSystemSchemeException:hdfs
  8. JAVA将list2合并到list1_java如何将两个list合并的问题
  9. 最全LinuxC语言系统开发资源视频资源
  10. Core Animation基础 1
  11. SQL进阶:数据中间表,多表取身份证号-整理-匹配多表-合并整理
  12. DivCss 布局应用案例实践总结
  13. phpStudy JspStudy 2016 更新下载,新版支持php7.0
  14. FOC 电流环PI控制器出来后为什么是电压?整定参数跟电机参数有关系吗?
  15. SQLite3下载与安装
  16. 关于c4d默认渲染器的玻璃材质调试
  17. 亚马逊运营怎么做广告?六大方法!
  18. 如何提高程序员的工作效率 这几招就够了
  19. Linux——Makefile文件
  20. 大数据技术原理与应用之【云数据库】习题

热门文章

  1. 致谢zyf2000,仅是你的备份,留念和记录学习C++的足迹
  2. 计算机仿真电路实验感想,单相桥式全控整流电路实验心得体会
  3. cad怎么画立体图形教学_CAD怎么画三维图形? cad绘制立体的室内装修图的教程
  4. git clone 的--single-branch和--depth参数
  5. Sqlite字段长度填坑
  6. php实现飘窗,装配式飘窗的制作方法
  7. 【POI】导出Excel自适应列宽
  8. Outlook2013 邮件签名设置
  9. Prolog编程求解图搜索问题
  10. igs时间和utc_UTC时间与北京时间的差多久?