Data Binding 详解(一)-从零开始
知是行之始,行是知之成。
文章配套的 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 类。它的主要改变有:
- 新的编译器是增量编译 Binding 类,这在大多数情况下加快了编译速度。
- library 模块的 Binding 类会被编译并打包到 AAR 文件中。 依赖这些库的应用程序不再需要重新生成 Binding 类。
- 老版本在编译出错时,经常会出现一些与真真错误不符合的提示,这个问题在新版本中已经做了修改。
- 绑定适配器(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 }
中,如果 user
为 null
,则 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 详解(一)-从零开始相关推荐
- java data使用_@Data注解详解及使用方法-Fun言
@Data作用 去除Getter,Setter,equals,hashCode,toString方法,@Data注解在类上时,简化java代码编写,为该类提供读写属性.简单来说就是不用再手动添加get ...
- 一文搞定 Spring Data Redis 详解及实战
转载自 一文搞定 Spring Data Redis 详解及实战 SDR - Spring Data Redis的简称. Spring Data Redis提供了从Spring应用程序轻松配置和访问 ...
- Ext.data.GroupingStore详解
Ext.data.GroupingStore详解 Ext.data.GroupingStore 继承自Ext.data.Store,为Store增加了分组功能.其它用法与Store一致,惟一需要注意的 ...
- 【转载】salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解...
salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解 建立好的数据表在数据库中查看有很多方式,本人目前采用以下两种方式查看数据表. 1.采用schema ...
- mysql的load data_【MySQL】load data语句详解(一)
作者 罗小波 沃趣科技高级MySQL数据库工程师 load data语句详解 背景 数据库版本:MySQL 5.7.18 服务器信息:本地到处导入在10.10.30.241上演示,local远程导入 ...
- html css data-,HTML+CSS入门 HTML自定义data属性详解
本篇教程介绍了HTML+CSS入门 HTML自定义data属性详解,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门.< 可以在HTML标签上添加任意以 "data-&q ...
- 25.消除不相关的细节/裂缝桥接(形态学 --膨胀与腐蚀详解 )--- OpenCV从零开始到图像(人脸 + 物体)识别系列
本文作者:小嗷 微信公众号:aoxiaoji 吹比QQ群:736854977 简书链接:https://www.jianshu.com/u/45da1fbce7d0 本文你会找到以下问题的答案: 形态 ...
- Tensorflow数据预处理之tf.data.TFRecordDataset---TFRecords详解\TFRecords图像预处理
目录 1.概述 2.预处理数据 2.1.常量定义 2.2.导入库 2.3.从train.txt文件中读取图片-标签对 2.4.预处理图片并保存 2.5.调用main函数 3.读取预处理后的数据 3.1 ...
- ajax jsonp 解析data,jsonp详解
title: jsonp详解 tags: categories: ajax不允许跨域获取数据 说明,假定后端语言是 PHP script标签 jsonp的原理:script标签具有跨域性,可以利用Sc ...
- Android vector Path Data画图详解
下面来解释一下"M 100,240 C510,300 80,100 300,160 H40 v80"这样字符串的意义. 分为四种情况来解释: 1. 移动指令:Move Comm ...
最新文章
- 腾讯AI开源框架Angel 3.0重磅发布:超50万行代码,支持3种算法,打造全栈机器学习平台...
- IoT和AI如何让企业在疫情期间重启业务
- U盘安装Linux CentOS 6.5 64位操作系统(来自互联网)
- easyUI的图标设置
- Android 插件化原理解析——Hook机制之AMSPMS
- levedb 导入 mysql_LevelDB-初始篇
- Flink 1.9 写入HDFS报错 UnsupportedFileSystemSchemeException:hdfs
- JAVA将list2合并到list1_java如何将两个list合并的问题
- 最全LinuxC语言系统开发资源视频资源
- Core Animation基础 1
- SQL进阶:数据中间表,多表取身份证号-整理-匹配多表-合并整理
- DivCss 布局应用案例实践总结
- phpStudy JspStudy 2016 更新下载,新版支持php7.0
- FOC 电流环PI控制器出来后为什么是电压?整定参数跟电机参数有关系吗?
- SQLite3下载与安装
- 关于c4d默认渲染器的玻璃材质调试
- 亚马逊运营怎么做广告?六大方法!
- 如何提高程序员的工作效率 这几招就够了
- Linux——Makefile文件
- 大数据技术原理与应用之【云数据库】习题