生成的绑定类

数据绑定库会生成绑定类,您可以使用这些类来访问布局的变量和视图。本文档介绍了如何创建和自定义生成的绑定类。

生成的绑定类会将布局变量与布局中的视图相关联。您可以自定义绑定的名称和软件包。所有生成的绑定类都继承自 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);

如果您在 FragmentListViewRecyclerView 适配器内使用数据绑定项,则可能需要使用绑定类的 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 的每个视图创建一个不可变字段。例如,数据绑定库根据以下布局创建类型为 TextViewfirstNamelastName 字段:

<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 不如没有数据绑定时的必要性,但在有些情况下,仍然需要通过代码访问视图。

变量

数据绑定库会为布局中声明的每个变量生成访问器方法。例如,以下布局在绑定类中为 userimagenote 变量生成了 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>

ViewStubs

与普通视图不同,ViewStub 对象最初以不可见视图的形式运行。当它们变为可见或明确膨胀后,它们会通过膨胀另一个布局在布局中自行替换。

由于 ViewStub 会从视图层次结构中消失,因此绑定对象中的视图也必须消失,才能让垃圾回收被垃圾回收。由于视图是最终视图,因此 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>

其他资源

如需详细了解数据绑定,请参阅下面列出的其他资源。