DataBinding 官方文档 翻译笔记
2018-01-19 18:21
429 查看
Data Binding Library
作用 : 在声明式布局的时候,最小化 页面布局和应用逻辑 之间的glue code (胶水代码)。前提
1. Android 2.1(API level 7+)
2. Gradle 1.5.0- alpha 1
环境搭建
确保已经安装了绑定库配置gradle脚本
开发工具 android studio 1.3 …
android { dataBinding{ enabled = true } }
注意: 如果应用程序模块中使用了数据绑定库,则APP也需要配置gradle脚本
Data Binding Compiler V2
在 Android gradle 插件 3.1.0 Cannary 6 中 附带了 可选的新 编译器。如果想使用新的DataBinding 编译器 ,可以在 gradle.properties 文件中添加android.databinding.enableV2=true
In compiler V2:
- VIewBinding 系列的类 将在java compiler 编译之前 由 Android Gradle Plugin 生成。这样可以避免 因为不相关的原因导致 java compiler 失败 ,从而导致得到太多误报错误。
- 在V1中 ,binding 系列的类将会在app编译完成后再次生成(去分享生成的代码并关联到 常量‘BR’ 和 ‘R’ 文件 )。在V2 中,绑定库为多模块项目 将 保留 生成的binding 系列类和映射信息 从而 显著提高 数据绑定性能。
注意: 新的V2编译器 是向后不兼容,所以使用v1编译的库不能 被V2使用,反之亦然。
V2 删除了一些 很少使用的功能 去允许如下更改:
* 在V1,一个应用程序可以在依赖中 提供 可以重写覆盖 原适配器的 binding adapters ,但在 V2 中 binding适配器 只能在 本身的模块/应用中和它的依赖中产生作用
* 先前,如果一个布局文件在两个或者多个不同的资源配置中 却被具有相同 id 但不同类的 VIew 所装载,DataBinding 将会找到最共同的父类。在V2,这将会默认配置给VIew 当类型在配置文件中不匹配。HeHe
* 在V2编译器下,不同模块不能再manifest清单中配置相同的包名,因为DataBinding 将会使用 包名来生成绑定映射器。
Data Binding Layout Files
数据绑定布局文件略有不同,它是以layout为root tag 紧随着 数据元素
data和视图 根元素view root element。 视图根元素就是原来不适用数据绑定框架的布局文件。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </LinearLayout> </layout>
布局文件中可以使用 包括数据描述属性 的 变量标签 。for example:
<variable name="user" type="com.example.User"/>
常用的表达式 方式
@{}
数据对象
数据对象可以是 普通 POJO类 和 JavaBeans类。假设引用 @{viewModel.useName} 等价于 公有属性 userName 等价于 公有get方法 getUserName() 等价于 userName() 方法。
绑定数据
默认的 ,一个Bainding 类 会基于 布局文件名 生成,翻译布局文件名以 Pascal case (命名方法) 并且以”Binding” 结尾。创建Binding的最简单方法是在inflating 过程中执行例如:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); User user = new User("Test", "User"); binding.setUser(user); }
获取视图的方式
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
在listview 或者recycleView中使用DataBinding
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); //or ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
事件处理
有两种方式去处理事件:1. Method References:(方法引用): 开发者可以引用符合监听器方法签名的方法,当表达式被评估为方法引用的时候,数据绑定框架将会把方法引用和所有者对象包装在一个监听器中,并且将监听器赋给视图。如果表达式为空 ,将不会生成监听器。
2. 监听器binding ,用一些Lanbda表达式,原理与方法引用类似,当事件分发时,监听器将评估lambda表达式。Lambda ( 提取对应监听方法的入参 ) -> function(自定义传参 (可使用入参 变量 ))
避免复杂的监听器
原则是 是布局文件可阅读,可维护性更高。存在一些特殊的点击事件,它们需要的别的属性 而不是
android:onClick去避免冲突.
如下:
Class Listener Setter Attribute
SearchView setOnSearchClickListener(View.OnClickListener) android:onSearchClick
ZoomControls setOnZoomInClickListener(View.OnClickListener) android:onZoomIn
ZoomControls setOnZoomOutClickListener(View.OnClickListener) android:onZoomOut
布局细节
import 0..more
类似java中引用类。类名冲突
<< 4000 span class="hljs-title">import type="android.view.View"/> <import type="com.example.real.estate.View" alias="Vista"/>
导入的类型可以用作于变量和类型引用
<data> <import type="com.example.User"/> <import type="java.util.List"/> <variable name="user" type="User"/> <variable name="userList" type="List<User>"/> </data>
Variables
变量类型将会在编译的时候被检查,如果类型体现了它们 实现了,Observable 或者observable.collection 接口,那么变量将可被观察。生成的binding类将会有setter getter 方法对每一个被描述的变量。在setter方法被执行前,默认值将会是java 默认值,,引用对象 == null int == 0 Boolean == false
binding表达式将会生成一个名叫 context的变量,变量的值是从 View的 getContext() 方法中获取.
Custom Binding Class Names(自定义 绑定类 名称)
默认地,一个绑定类将会基于布局文件名 生成 例如 : contact_item.xml —> ContactItemBinding类,然后该类放在 databinding包下。但是Binding类可以放在不同的包下可自定义命名
<data class="包名.类名"> </data>
Include
用于 布局文件的引用不支持引用布局作为合并元素的直接子元素。
表达式语言
与java有共同特征的
Mathematical 数学运算符 + - / * % String 字符串拼接 concatenation + Logical 逻辑运算 && || Binary 二进制运算 & | ^ Unary 一元运算符 + - ! ~ Shift 位运算 >> >>> << Comparison 比较运算符 == > < >= <= instanceof 继承关系 Grouping () Literals - character, String, numeric, null Cast Method calls Field access Array access [] Ternary operator ?:
缺少的方法
java中可以用 lambda中无法使用- this - super - new - Explicit generic invocation 显示泛型调用
空值 合并操作
空合并操作符??选择左边的值,如果左值不为空 否则 右值
android:text="@{user.displayName ?? user.lastName}"等价
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
避免空指针异常
生成的数据绑定代码 将会自动检查空值和避免空指针异常。 当遇到空值 databinding将会使用各类型默认值代替集合操作
公共集合包括 arrays lists sparse lists 和 map ,也许会通过操作符[]来方便使用
举例:
<data> <import type="android.util.SparseArray"/> <import type="java.util.Map"/> <import type="java.util.List"/> <variable name="list" type="List<String>"/> <variable name="sparse" type="SparseArray<String>"/> <variable name="map" type="Map<String, String>"/> <variable name="index" type="int"/> <variable name="key" type="String"/> </data> … android:text="@{list[index]}" … android:text="@{sparse[index]}" … android:text="@{map[key]}"
String Literals 字符串文字
android:text='@{map["firstName"]}' android:text="@{map[`firstName`}" android:text="@{map['firstName']}"
Resources 资源文件
使用普通的表达式作为表达式的一部分是可以获取资源文件android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
格式化字符串 和 复数是可以通过 参数来评估的
android:text="@{@string/nameFormat(firstName, lastName)}" android:text="@{@plurals/banana(bananaCount)}"
一些资源需要明确的类型评估
Type | Normal Reference | Expression Reference |
---|---|---|
String[] | @array | @stringArray |
int[] | @array | @intArray |
TypedArray | @array | @typedArray |
Animator | @animator | @animator |
StateListAnimator | @animator | @stateListAnimator |
color int | @color | @color |
ColorStateList | @color | @colorStateList |
数据对象 Data Object
任何 POJO 都可以用于 DataBinding ,但是修改一个POJO 不会产生UI更新。Databinding的真正能力是给你的数据对象们通知的能力在器数据被修改时。 有3种 不同的 数据修改通知机制。Observable objects、observable fields 和 observable collectionsObservable Object
实现Observable 接口的类 允许 绑定一个 附加的侦听器 到绑定的对象上,去监听所有的属性变化。
Observable接口具有添加和删除侦听器的机制,但是通知是由开发者决定的。为了是开发更加容易,产生了一个BaseObservable 的基类来完成 侦听器注册功能。通过给 getter方法一个Bindable 注解 和 setter中进行通知。
private static class User extends BaseObservable { private String firstName; private String lastName; @Bindable public String getFirstName() { return this.firstName; } @Bindable public String getLastName() { return this.lastName; } public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR.firstName); } public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); } }
Bindable 注解 在编译期间 在BR class 文件中生成一个条目。BR文件将会生成在Module 包下。
如果 数据类的基类不能被修改,通过使用简便的PropertyChangeRegistry实现的 Observable 接口更有效的存储和通知监听器。
- Observable fields
当创建观察量的工作量很小,开发者可能会为了缩小开发时间,而采用ObservableField方式和其同级对象 ObservableBoolean ObservableByte ObservableChar ObservableShort ObservableInt ObservableLong ObservableFloat ObservableDouble ObservableParcelable
可观察属性将会生成一个具有单个字段的可观察对象。原始版本将会在访问阶段 避免装箱和拆箱操作。为了使用将会在数据类中使用FInal field
for example:
private static class User { public final ObservableField<String> firstName = new ObservableField<>(); public final ObservableField<String> lastName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(); }
数据的获取方式
user.firstName.set("Google"); int age = user.age.get();
observable collection
一些应用使用更加动态的结构去存储数据对象。可观察集合可以通过keys值来获取其数据对象
ObservableArrayMap 是一个有效地方法当keys是索引对象 ,比如是 String
code for example:
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("firstName", "Google"); user.put("lastName", "Inc."); user.put("age", 17);
生成Binding Generated Binding
生成的Binding类 会根据xml 文件名 和配置生成 ,,继承自 ViewDataBinding。Creating 生成过程
Binding的应该立马在Inflation 视图文件后生成 以确保 在Layout中使用表达式bingding View而不影响视图结构。有几种方法去绑定 Layout,最常见的方法是使用 Binding Class的静态类方法。静态类方法的Inflate方法将会一次性 infaltes 视图结构 完成绑定。
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);
If the layout was inflated using a different mechanism, it may be bound separately:
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
Sometimes the binding cannot be known in advance. In such cases, the binding can be created using the DataBindingUtil class:
parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);
Views With IDs
如果布局中的View 包含Id 属性 ,则框架会为他们各自生成一个公有常量。Binding将会在视图上进行单个传递,通过ID获取视图。这种机制对一些视图将会比使用findVIewById更加高速。for Example:
<TextView id = "firstName" android:layout_width="wrap_content" android:layout_height="wrap_content"/> 在bingding中 生成 public final TextView firstName; 使用: binding.firstName;
Variables
每一个变量 将会被给与一个访问方法<data> <import type="android.graphics.drawable.Drawable"/> <variable name="user" type="com.example.User"/> <variable name="image" type="Drawable"/> <variable name="note" type="String"/> </data>
生成的访问方法:
public abstract com.example.User getUser(); public abstract void setUser(com.example.User user); public abstract Drawable getImage(); public abstract void setImage(Drawable image); public abstract String getNote(); public abstract void setNote(String note);
Advanced Binding 高级Binding
Dynamic Variables
有时候 特定的binding类将不会被知道,比如在RecycleView.Adapter 操作针对任意布局将不会知道其对应的指定Binding Class。它必须在onBindViewHolder 中 分配Binding值。forExample使用 BindingHolder 代替ViewHolder 使用期getBinding 方法 来回去 ViewDataBinding 对象。
public void onBindViewHolder(BindingHolder holder, int position) { final T item = mItems.get(position); holder.getBinding().setVariable(BR.item, item); holder.getBinding().executePendingBindings();
Immediate Binding 立刻Binding
当变量 或者 可观察对象 改变时,,binding 将会计划改变 在下一帧的时候。有时候,必须立刻binding ,解决方法 是使用 executePendingBindings() 方法Background Thread
牛逼的功能You can change your data model in a background thread as long as it is not a collection. Data binding will localize each variable / field while evaluating to avoid any concurrency issues.
Attribute Setters
Automatic Setters 自动赋值
对于属性,data binding 尝试 去寻找属性的setAttribute 方法。相对于属性名称本身,属性的命名空间本部重要。举一个例子: 在表达式中关联到 TextView的属性 android:text ,databinding 将会去寻找 setText方法。如果表达式返回的是一个 int ,databinding 将会去寻找 setText(int) 方法。请注意表达式返回的类型是否正确,必要时要进行 转换操作。注意: data Binding 将会依旧工作 即使 关联的View不存在 命名的属性。所以你可以简单=地生成一些属性 进行setter 通过 databinding 。举例:DrawerLayout 拥有大量没有xml 属性的setter 方法 :
<android.support.v4.widget.DrawerLayout android:layout_width="wrap_content" android:layout_height="wrap_content" app:scrimColor="@{@color/scrim}" app:drawerListener="@{fragment.drawerListener}"/>
Renamed Setters 重命名Setter
一些attributes有拥有setter方法但不符合命名规则,对于这些方法,这些属性可以通过 BindingMethods 注解来关联。这必须和一个类相关联并且包含BindingMethod 方法。举例 android:tint 其真正关联的方法是 setImageTintList(ColorStateList)方法 而不是 setTint.@BindingMethods({ @BindingMethod(type = "android.widget.ImageView", attribute = "android:tint", method = "setImageTintList"), })
Custom Setters 自定义Setter
终于到接触过的@BindingAdapterSome attributes need custom binding logic. For example, there is no associated setter for the android:paddingLeft attribute. Instead, setPadding(left, top, right, bottom) exists. A static binding adapter method with the BindingAdapter annotation allows the developer to customize how a setter for an attribute is called.
The android attributes have already had BindingAdapters created. For example, here is the one for paddingLeft:
@BindingAdapter(“android:paddingLeft”)
public static void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
Binding adapters are useful for other types of customization. For example, a custom loader can be called off-thread to load an image.
Developer-created binding adapters will override the data binding default adapters when there is a conflict.
You can also have adapters that receive multiple parameters.
@BindingAdapter({“bind:imageUrl”, “bind:error”})
public static void loadImage(ImageView view, String url, Drawable error) {
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
Converters 转换器
## Object Conversions 对象转换器当一个对象从表达式中返回,将会自动从renamed 和 传统setters 选择一个setter方法,该对象将会转换成所选setter所需要的参数类型。
有时 转换时自动进行的。比如 background方法:背景将会是一个Drawable ,但是给的Color 是一个Int 所以,会需要Int 转换成ColorDrawable
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
Android Studio Support for Data Binding
Android Studio supports many of the code editing features for data binding code. For example, it supports the following features for data binding expressions:Syntax highlighting
Flagging of expression language syntax errors
XML code completion
References, including navigation (such as navigate to a declaration) and quick documentation
Note: Arrays and a generic type, such as the Observable class, might display errors when there are no errors.
相关文章推荐
- DataBinding 官方文档翻译学习笔记
- Log4j2官方文档翻译、学习笔记之二——Appender的分类及常用类型示例
- [cpp 编译]Autotools笔记 翻译自autotools官方文档
- spark mlib官方文档学习和翻译笔记(2)
- mysql官方文档阅读笔记(二)整体目录翻译
- Log4j2官方文档翻译、学习笔记之一——log4j2基础配置及功能概述
- Jinja2学习笔记暨官方文档的翻译
- db4o_8.0对象数据库官方文档翻译_学习笔记四
- db4o_8.0对象数据库官方文档翻译_学习笔记一
- spark mlib官方文档学习和翻译笔记(1)
- Jinja2学习笔记暨官方文档的翻译
- jsPlumb.jsAPI阅读笔记(官方文档翻译)
- Jinja2学习笔记暨官方文档的翻译 -- 转载
- Log4j2官方文档翻译、学习笔记之三——Layouts的分类及常用类型示例
- db4o_8.0对象数据库官方文档翻译_学习笔记二
- db4o_8.0对象数据库官方文档翻译_学习笔记三
- S a759 wift 3.1 官方文档翻译(一)——关于 Swift
- Solr入门之官方文档6.0阅读笔记系列(二)
- ansible官方文档翻译之变量
- [资料汇总]Leap Motion官方开发文档翻译