Android ViewBinding 使用详解

2,018 阅读3分钟

1. ViewBinding 是什么?

Android ViewBinding 是 Android 官方推出的一种数据绑定库,旨在简化视图和代码之间的交互,提供了一种类型安全的方式来访问视图的属性和方法。

ViewBinding 可以自动生成绑定视图的代码,避免手动 findViewById 的繁琐过程,使代码更加简洁。

2. 如何使用 ViewBinding

2.1 相关配置

build.gradle 文件中进行如下配置:

android {
    ... 
    buildFeatures { 
        viewBinding true 
    }
}

ViewBinding 会为每个 layout 布局文件生成一个对应的绑定类,如果希望忽略某一个布局文件,需要在该文件的根布局添加 tools:viewBindingIgnore="true" 属性:

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

在 Android 项目的 Gradle 配置中,buildFeatures 是 Android Gradle 插件(AGP)提供的一个关键配置块,用于按需启用或禁用特定编译时功能(如视图绑定、数据绑定、Compose 等)。它允许开发者更精细化地控制模块的功能模块化,避免引入不必要的依赖和代码生成,从而优化构建性能和 APK 体积。

2.2 用法

假设 activity_main.xml 如下:

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

生成绑定类的名称命名规则:将 XML 文件的名称转换为 Pascal 大小写形式,并在末尾添加“Binding”。activity_main.xml -> ActivityMainBinding

每个绑定类还包含一个 getRoot() 方法,直接可以获取到对应布局文件的根视图的引用(LinearLayout)。

用法总结:通过绑定类的 inflate() 方法获取绑定类实例,此方法需传入 LayoutInflater 的实例,然后调用绑定类的 getRoot() 方法即可获取根视图。

2.1.1 在 Activity 中使用

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityMainBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
    binding.name.setText(viewModel.getName());
    binding.button.setOnClickListener(new View.OnClickListener() {
        viewModel.userClicked()
    });
}
  1. 通过绑定类的 inflate() 方法获取绑定类实例。
  2. 调用 getRoot() 方法获取根视图。
  3. 将根视图传递给 setContentView

2.1.2 在 Fragment 中使用

private ActivityMainBinding binding;

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

@Override
public void onDestroyView() {
    super.onDestroyView();
    // Fragment 的存在时间比其视图长。
    binding = null;
}
  1. 通过绑定类的 inflate() 方法获取绑定类实例。
  2. 调用 getRoot() 方法获取根视图。
  3. onCreateView 方法中返回根视图。

2.1.3 针对不同配置下的 layout 文件

# in res/layout/example.xml
<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml
<EditText android:id="@+id/user_bio" />

TextView 是 TextView 和 EditText 的公共基类。但是 ViewBinding 无法识别,系统会自动转为 View 对象,需手动转为 TextView 对象。

为了解决这个缺陷,ViewBinding 提供了 tools:viewBindingType 属性,用于告知编译器要在生成的代码中使用何种类型:

# 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" />

3. 原理

编译的时候会去扫描 layout 文件,生成对应的 binding 类:

image.png

image.png

其内部实现很简单,就是通过传入的 LayoutInflater 对象去加载相应的布局文件,并返回了 rootView。简化视图和代码之间的交互,使代码更简洁。

用法总结:通过绑定类的 inflate() 方法获取绑定类实例,此方法需传入 LayoutInflater 的实例,然后调用绑定类的 getRoot() 方法即可获取根视图。

点击阅读 LayoutInflater 的原理:Android LayoutInflater 源码详解