View 绑定   Android Jetpack 的一部分。

视图绑定是一项可让您更轻松地编写与视图交互的代码的功能。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。

在大多数情况下,视图绑定会替代 findViewById

设置

视图绑定功能可按模块启用。如需在模块中启用视图绑定,请在模块级 build.gradle 文件中将 viewBinding build 选项设置为 true,如以下示例所示:

GroovyKotlin
android {
    ...
    buildFeatures {
        viewBinding true
    }
}
android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

如果您希望在生成绑定类时忽略某个布局文件,请将 tools:viewBindingIgnore="true" 属性添加到相应布局文件的根视图中:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

用法

为某个模块启用视图绑定功能后,系统会为该模块中包含的每个 XML 布局文件生成一个绑定类。每个绑定类均包含对根视图以及具有 ID 的所有视图的引用。系统会通过以下方式生成绑定类的名称:将 XML 文件的名称转换为 Pascal 大小写形式,并在末尾添加“Binding”一词。

例如,假设有一个名为 result_profile.xml 的布局文件,其中包含以下内容:

<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>

所生成的绑定类的名称就为 ResultProfileBinding。此类具有两个字段:一个是名为 nameTextView,另一个是名为 buttonButton。该布局中的 ImageView 没有 ID,因此绑定类中不存在对它的引用。

每个绑定类还包含一个 getRoot() 方法,用于为相应布局文件的根视图提供直接引用。在此示例中,ResultProfileBinding 类中的 getRoot() 方法会返回 LinearLayout 根视图。

以下几个部分介绍了生成的绑定类在 activity 和 fragment 中的使用。

在 Activity 中使用视图绑定

如需设置绑定类的实例以供 activity 使用,请在 activity 的 onCreate() 方法中执行以下步骤:

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Activity 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. 将根视图传递到 setContentView(),使其成为屏幕上的活动视图。

这些步骤如以下示例所示:

KotlinJava
private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}
private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

您现在即可使用该绑定类的实例来引用任何视图:

KotlinJava
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

在 Fragment 中使用视图绑定

如需设置绑定类的实例以供 Fragment 使用,请在 fragment 的 onCreateView() 方法中执行以下步骤:

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Fragment 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. onCreateView() 方法返回根视图,使其成为屏幕上的活动视图。
KotlinJava
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}
private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater,
                          ViewGroup container,
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}

您现在即可使用该绑定类的实例来引用任何视图:

KotlinJava
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

针对不同的配置提供提示

在多个配置中声明视图时,有时需要根据具体布局使用不同的视图类型。以下代码段展示了此示例:

# in res/layout/example.xml

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" />

在这种情况下,您可能希望生成的类公开类型为 TextView 的字段 userBio,因为 TextView 是公共基类。由于技术限制,视图绑定代码生成器无法确定这一点,而是会改为生成 View 字段。这需要稍后使用 binding.userBio as TextView 对字段进行类型转换。

为了解决此限制,视图绑定支持 tools:viewBindingType 属性,让您可以告知编译器在生成的代码中使用哪种类型。在上例中,您可以使用此属性让编译器将字段生成为 TextView

# in res/layout/example.xml (unchanged)

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />

在另一个示例中,假设您有两个布局,一个包含 BottomNavigationView,另一个包含 NavigationRailView。这两个类都扩展了 NavigationBarView,其中包含大多数实现详细信息。如果您的代码不需要确切知道当前布局中存在哪个子类,则可以在两个布局中使用 tools:viewBindingType 将生成的类型设置为 NavigationBarView

# in res/layout/navigation_example.xml

<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

# in res/layout-w720/navigation_example.xml

<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

在生成代码时,视图绑定无法验证此属性的值。为避免编译时和运行时错误,该值必须满足以下条件:

  • 该值必须是继承自 android.view.View 的类。
  • 该值必须是其所放置的标记的父类。例如,以下值不起作用:

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
      <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
    
  • 最终类型必须在所有配置中一致解析。

与 findViewById 的区别

与使用 findViewById 相比,视图绑定具有一些很显著的优点:

  • Null 安全:由于视图绑定会创建对视图的直接引用,因此不存在因视图 ID 无效而引发 Null 指针异常的风险。此外,如果视图仅出现在布局的某些配置中,则绑定类中包含其引用的字段会使用 @Nullable 标记。
  • 类型安全:每个绑定类中的字段均具有与它们在 XML 文件中引用的视图相匹配的类型。这意味着不存在发生类转换异常的风险。

这些差异意味着布局和代码之间的不兼容将会导致构建在编译时(而非运行时)失败。

与数据绑定的对比

视图绑定和数据绑定均会生成可用于直接引用视图的绑定类。但是,视图绑定旨在处理更简单的用例,与数据绑定相比,具有以下优势:

  • 更快的编译速度:视图绑定不需要处理注解,因此编译时间更短。
  • 易于使用:视图绑定不需要特别标记的 XML 布局文件,因此在应用中采用速度更快。在模块中启用视图绑定后,它会自动应用于该模块的所有布局。

另一方面,与数据绑定相比,视图绑定也具有以下限制:

考虑到这些因素,在某些情况下,最好在项目中同时使用视图绑定和数据绑定。您可以在需要高级功能的布局中使用数据绑定,而在不需要高级功能的布局中使用视图绑定。

其他资源

如需详细了解视图绑定,请参阅以下其他资源:

博客

视频

Discover the latest app development tools, platform updates, training, and documentation for developers across every Android device.

更新于 Sep 20, 2024

Discover the latest app development tools, platform updates, training, and documentation for developers across every Android device.

更新于 Sep 20, 2024

浏览有关界面层库的应用架构指南,了解构建环境、Android Studio 对数据绑定的支持等。

更新于 Aug 29, 2024