数据绑定库会生成绑定类,您可以使用这些类访问布局的变量和视图。本文档介绍了如何创建和自定义生成的绑定类。
生成的绑定类将布局变量与布局中的视图关联起来。您可以自定义绑定的名称和软件包。所有生成的绑定类都继承自 ViewDataBinding
类。
每个布局文件都会生成一个绑定类。默认情况下,类名是布局文件名转换为 Pascal 大小写并添加了 Binding 后缀。例如,如果布局文件名是 activity_main.xml
,则相应的生成类是 ActivityMainBinding
。此绑定类包含从布局属性到布局视图的所有绑定,并知道如何为绑定表达式分配值。
创建绑定对象
绑定对象会在布局膨胀后立即创建,以确保在它与布局中的视图及表达式绑定之前,视图层次结构不会被修改。将对象绑定到布局的最常用方法是使用绑定类中的静态方法。您可以使用绑定类的 inflate()
方法膨胀视图层次结构并将其绑定到对象,如以下示例所示:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater) setContentView(binding.root) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater()); setContentView(binding.root); }
inflate()
方法还有一个替代版本,除了 LayoutInflater
对象外,它还接受一个 ViewGroup
对象,如以下示例所示:
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)
Java
MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);
如果布局是使用不同的机制膨胀的,您可以单独绑定它,如下所示:
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)
Java
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
有时您可能不知道绑定类型。在这种情况下,您可以使用 DataBindingUtil
类创建绑定,如以下代码片段所示:
Kotlin
val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent) val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)
Java
View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bind(viewRoot);
如果您在 Fragment
、ListView
或 RecyclerView
适配器中使用数据绑定项,您可能更喜欢使用绑定类的 inflate()
方法或 DataBindingUtil
类,如以下代码示例所示:
Kotlin
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // or val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
Java
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); // or ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
带 ID 的视图
数据绑定库会为布局中每个具有 ID 的视图在绑定类中创建一个不可变字段。例如,数据绑定库会从以下布局创建类型为 TextView
的 firstName
和 lastName
字段:
<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}"
android:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>
该库通过一次遍历从视图层次结构中提取视图(包括 ID)。这种机制可能比为布局中的每个视图调用 findViewById()
方法更快。
与不使用数据绑定的情况相比,ID 并非那么必要,但在某些情况下,仍然需要从代码中访问视图。
变量
数据绑定库会为布局中声明的每个变量生成访问器方法。例如,以下布局会在绑定类中为 user
、image
和 note
变量生成 setter 和 getter 方法:
<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>
ViewStub
与普通视图不同,ViewStub
对象最初是不可见的视图。当它们变为可见或被显式膨胀时,它们会通过膨胀另一个布局来替换自身在布局中的位置。
由于 ViewStub
从视图层次结构中消失,绑定对象中的视图也必须消失,以便进行垃圾回收。由于视图是 final 的,ViewStubProxy
对象会取代生成的绑定类中的 ViewStub
,让您在 ViewStub
存在时访问它,并在 ViewStub
膨胀时访问膨胀后的视图层次结构。
当膨胀另一个布局时,必须为新布局建立绑定。因此,ViewStubProxy
必须监听 ViewStub
的 OnInflateListener
并在需要时建立绑定。由于一次只能存在一个监听器,ViewStubProxy
允许您设置一个 OnInflateListener
,它会在建立绑定后调用该监听器。
即时绑定
当变量或可观察对象发生更改时,绑定会在下一帧之前计划更改。然而,有时必须立即执行绑定。要强制执行,请使用 executePendingBindings()
方法。
动态变量
有时,特定的绑定类是未知的。例如,针对任意布局操作的 RecyclerView.Adapter
不知道具体的绑定类。它必须在调用 onBindViewHolder()
方法期间分配绑定值。
在以下示例中,RecyclerView
绑定的所有布局都具有 item
变量。BindingHolder
对象有一个 getBinding()
方法,返回 ViewDataBinding
基类。
Kotlin
override fun onBindViewHolder(holder: BindingHolder, position: Int) { item: T = items.get(position) holder.binding.setVariable(BR.item, item); holder.binding.executePendingBindings(); }
Java
public void onBindViewHolder(BindingHolder holder, int position) { final T item = items.get(position); holder.getBinding().setVariable(BR.item, item); holder.getBinding().executePendingBindings(); }
后台线程
您可以在后台线程中更改数据模型,只要它不是集合即可。数据绑定会在评估期间本地化每个变量或字段,以避免任何并发问题。
自定义绑定类名称
默认情况下,绑定类是根据布局文件名生成的,以大写字母开头,移除下划线 (_),将下一个字母大写,并添加 Binding 后缀。例如,布局文件 contact_item.xml
会生成 ContactItemBinding
类。该类放置在模块软件包下的 databinding
软件包中。例如,如果模块软件包是 com.example.my.app
,则绑定类会放置在 com.example.my.app.databinding
软件包中。
通过调整 data
元素的 class
属性,可以重命名绑定类或将其放置在不同的软件包中。例如,以下布局会在当前模块的 databinding
软件包中生成 ContactItem
绑定类:
<data class="ContactItem">
...
</data>
您可以通过在类名前加上句点来在不同的软件包中生成绑定类。以下示例会在模块软件包中生成绑定类:
<data class=".ContactItem">
...
</data>
您也可以使用完整的软件包名称来指定要生成绑定类的位置。以下示例会在 com.example
软件包中创建 ContactItem
绑定类:
<data class="com.example.ContactItem">
...
</data>
其他资源
要详细了解数据绑定,请参阅以下其他资源。