您的位置:首页 > 其它

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 objectsobservable fieldsobservable collections

Observable 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

终于到接触过的@BindingAdapter

Some 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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: