来自官方的Android数据绑定(Data Binding)框架①

作者: rain 分类: 移动 发布时间: 2015-06-04 10:09 6 条评论

今年的Google IO 大会上,Android 团队发布了一个数据绑定框架(Data Binding Library)。以后可以直接在 layout 布局 xml 文件中绑定数据了,无需再 findViewById 然后手工设置数据了。其语法和使用方式和 JSP 中的 EL 表达式非常类似。

Data Binding Library 是一个 support 库,支持 Android 2.1+ 版本 (API level 7+)。 由于该框架需要使用编译器来生成很多代码,所以需要配合最新版本的 Android Studio (1.3.0-beta1 + 版本)才能使用。

另外需要注意的是,Data Binding Library 还处于 beta 测试阶段,所以 API 还不稳定,随时可能会修改 API 接口,同时还有很多 BUG, 如果您使用过程中遇到了 bug ,可以到这里反馈: https://code.google.com/p/android-developer-preview/

下面来介绍下如何使用 Data Binding Library

  1. 确保你的 Android Studio 为 1.3.0-beta1 或者更新版本
  2.  通过 Android SDK manager 来下载最新的 Support repository,里面包含了 Data Binding Library。
  3. 在项目的 gradle 配置文件中添加依赖项:
  4. 由于上面的依赖项目前在 jcenter 服务器中,所以确保 repositories 中包含 jcenter。
  5. 在每个需要使用 Data Binding 功能的模块的 gradle 配置文件中启用该插件(添加在 android 插件之后),

Data Binding 在编译的时候依赖很多其他库。 1.0-rc0 依赖的第三方库如下:

在 Layout 布局文件中使用数据绑定(Data Binding)

数据绑定表达式

Data-binding 布局文件和常规的 布局文件是不一样的, 其根元素为 layout 然后里面有个 data 和一个 View 元素。 这个 View 元素的内容就是常规的布局文件内容。

在 data 元素中使用 variable 来声明在布局文件中使用的变量。

<variable name=”user” type=”com.example.User”/>

布局文件中引用变量值的属性通过 @{} 格式来调用。下面的示例设置 TextView 的文字为 user 对象的 firstName 的值。

<TextView android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@{user.firstName}”/>

数据对象(Data Object)

假设上面引用的 user 对象为一个 POJO( plain-old Java object)

这种类型对象的数据从来不变。 在应用中经常有这种数据。 也可以使用 JavaBeans 对象:

在数据绑定中,这两种对象是一样的。 表达式 @{user.firstName} 在第一种情况中会使用 firstName 变量的值;在后一种情况中会使用 getFirstName() 函数的返回值。

绑定数据(Binding Data)

默认情况下, 自动生成的 Binding 类名字为 布局文件的名字加上 Binding 后缀,使用驼峰命名法。 例如上面的 activity_main.xml 生成的 Binding 类为 ActivityMainBinding。 该类包含了所有把布局文件的变量值应用到 View 上的代码,并且知道如何处理绑定表达式。 最简单的获取绑定类对象的方式如下:

上面三行代码即可完成数据绑定的工作。 现在运行程序,就可以看到 Test User 字符串已经设置到 TextView 上了。

也可以通过如下方式获取 Binding 对象:

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

如果您在 ListView 或者 RecyclerView 的 adapter 中使用数据绑定,则推荐使用如下的方式:

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

布局文件解析

导入(Imports)

在 data 元素中可以使用多个 import 元素来导入需要引用的对象,和 Java 的import  语句一样。

<data>
<import type=”android.view.View”/>
</data>

然后,你就可以在表达式中使用 View 对象了。

<TextView
android:text=”@{user.lastName}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:visibility=”@{user.isAdult ? View.VISIBLE : View.GONE}”/>

如果遇到类名一样的情况下,可以使用 alias 来重命名:

<import type=”android.view.View”/>
<import type=”com.example.real.estate.View”
alias=”Vista”/>

这样就可以通过 Vista  来引用 com.example.real.estate.View 对象了。导入的对象也可以当做类型使用。

<data>
<import type=”com.example.User”/>
<import type=”java.util.List”/>
<variable name=”user” type=”User”/>
<variable name=”userList” type=”List&lt;User>”/>
</data>

注意,当前的 Android Studio 还没有支持导入解析,所以代码自动完成还没法使用。

使用类似 Java 类型强制转换的表达式:

<TextView
android:text=”@{((User)(user.connection)).lastName}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”/>

导入类型还可以使用静态函数和变量:

<data>
<import type=”com.example.MyStringUtils”/>
<variable name=”user” type=”com.example.User”/>
</data>

<TextView
android:text=”@{MyStringUtils.capitalize(user.lastName)}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”/>

和 Java 一样, java.lang.* 中的对象自动导入了。

变量(Variables)

data 元素中还可以使用 variable 来定义在布局文件表达式中使用的对象。

<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>

变量的类型在编译的时候就确定了,如果一个变量类型实现了 Observable https://developer.android.com/intl/zh-cn/tools/data-binding/guide.html#observable_objects 或者 是一个 observable 集合,则在编译的时候回监听该变量的值变化事件。 如果没有实现 Observable 接口,则不会监听。

如果有多个布局文件(配置不一样的情况下,例如 横屏和竖屏),多个布局文件中的变量会叠加一起。所以要保证变量的名字不能冲突。

生成的 binding 类中包含每个变量的 setter 和 getter 函数。 如果您没有调用 setter 函数,则表达式将使用每个对象的默认值,也就是 Java 对象的默认值 (对象为 null, int 为 0 等)

自定义 Binding 类的名字

默认生成的 Binding 类位于模块包的 databinding 子包中。例如 contact_item.xml 生成一个 ContactItemBinding 类,如果模块包名字为 com.example.my.app, 则该类的包名字为 com.example.my.app.databinding。

使用 data 元素的 class 属性可以自定义 Binding 类名字和包名字。
例如,下面的示例自定义 类名为 ContactItem。

<data class=”ContactItem”>

</data>

如果像把包名字修改为模块的包,则可以这样(前面多了一个 . ):
<data class=”.ContactItem”>

</data>

如果要单独设置一个包名字, 则可以这样:
<data class=”com.example.ContactItem”>

</data>

布局文件引用(Includes)

变量可以传递到布局文件引用的布局文件中:

上面的示例中,在 name.xml 和 contact.xml 布局文件中必须有一个 user 变量的定义。

表达式语言(Expression Language)

和 Java 表达式一样支持常见的表达式:

  • 数学表达式 + – / * %
  • 字符串链接 +
  • 逻辑操作符 && ||
  • 二元操作符 & | ^
  • 一元操作符 + – ! ~
  • Shift >> >>> <<
  • 比较 == > < >= <=
  • instanceof
  • Grouping ()
  • Literals – character, String, numeric, null
  • Cast
  • 函数调用
  • 值域引用(Field access)
  • 通过[]访问数组里面的对象
  • 三元操作符 ?:

示例:

  • android:text=”@{String.valueOf(index + 1)}”
  • android:visibility=”@{age &lt; 13 ? View.GONE : View.VISIBLE}”
  • android:transitionName=’@{“image_” + id}’

不支持的语法

  • this
  • super
  • new
  • 显示的泛型调用

空指针检查操作符(Null Coalescing Operator)
如果 ?? 左边的对象不是 Null 则使用 左边的对象,否则使用右边的对象。

android:text=”@{user.displayName ?? user.lastName}”

上面的表达式等价于:
android:text=”@{user.displayName != null ? user.displayName : user.lastName}”

属性引用(Property Reference)

属性应用很简单,例如
android:text=”@{user.lastName}”
分别在 user 对象中查找 值域、getter 函数或者 ObservableFields。

避免 NullPointerException

生成的数据绑定代码自动检查 Null 并且避免 NullPointerException。 例如,对于表达式 @{user.name} ,如果 user 是 null, 则表达式的值为默认值 null, 如果引用的为 user.age, age 为 int 类型,则默认值为 0.

集合

常见的集合可以使用 [] 操作符来引用里面的元素,例如 arrays, lists, sparse lists, 和 maps。

<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&lt;String>”/>
<variable name=”map” type=”Map&lt;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”]}’

如果属性值使用双引号定义,则需要使用 &quot; 或者反引号 (`)。
android:text=”@{map[`firstName`}”
android:text=”@{map[&quot;firstName&quot;]}”

资源

在常规表达式中也可以使用资源:
android:padding=”@{large? @dimen/largePadding : @dimen/smallPadding}”

带参数的字符串或者复数字符串也可以通过提供参数来使用:
android:text=”@{@string/nameFormat(firstName, lastName)}”
android:text=”@{@plurals/banana(bananaCount)}”

如果 复数字符串使用了多个变量,则需要提供所有的变量:

Have an orange
Have %d oranges

android:text=”@{@plurals/orange(orangeCount, orangeCount)}”

有些资源的引用方式有变化:

资源类型 布局 View 中引用方式 表达式引用方式
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

 

未完待续

本文出自 云在千峰,转载时请注明出处及相应链接。

本文永久链接: http://blog.chengyunfeng.com/?p=734

Ɣ回顶部