生成的绑定类

数据绑定库生成您可以用来访问布局的变量和视图的绑定类。 本文档演示了如何创建和自定义生成的绑定类。

生成的绑定类将布局变量与布局内的视图链接起来。 您可以自定义绑定的名称和包。 所有生成的绑定类都继承自ViewDataBinding类。

每个布局文件都会生成一个绑定类。 默认情况下,类的名称是布局文件的名称转换为帕斯卡大小写,并在其后添加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 的视图在绑定类中创建一个不可变字段。 例如,数据绑定库从以下布局创建firstNamelastName类型为TextView的字段

<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变量在绑定类中生成设置器和获取器方法

<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 必须监听 ViewStubOnInflateListener,并在需要时建立绑定。由于一次只能存在一个监听器,因此 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>

其他资源

要了解有关数据绑定的更多信息,请参阅以下其他资源。