Android Jetpack 系列(一)View Binding 视图绑定

1. 简介

在过去的Android开发中,通常会使用 findViewById() 方法来获取 XML 布局文件中的 View 对象,然后对该对象进行设置文本、设置是否可见、设置点击事件回调等视图操作。然而,这种获取和操作 View 对象的方式可能存在一些问题,例如:

  1. 如果 findViewById() 方法传入的是一个不存在的 View ID,在使用该对象时可能会导致空指针异常。
  2. 因为 findViewById() 方法是一个泛型方法,若传入的类型与布局文件中的 View 类型不一致,可能会导致类型异常。
  3. 这些异常通常在运行时发生,影响应用程序的稳定性。

View Binding 是 Android Jetpack 库的一部分,是一种可以替代使用 findViewById() 方法的技术,旨在简化 View 与代码之间的绑定过程。它会在编译时期为每个 XML 布局文件生成相应的绑定类(Binding class),该类包含了布局文件中每个有 ID 的 View 的引用。这样可以避免频繁手动调用 findViewById() 方法来获取 View 对象,从而让开发者直接通过 Binding class 访问布局文件中的 View,避免了空指针或类型转换异常的发生。

2. 启用 View binding

如果需要在工程项目中启用 View binding,需要先在项目模块级 buid.gradle 文件中将 viewBinding 构建选项设置为 true, 如:

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

因为 View Binding 开启后,会在编译时期为每个 XML 布局文件生成相应的 Binding class,这样也会存在一定的编译时间增加和包大小增加,若你明确某个布局文件不需要生在 Binding class,可以将 tools:viewBindingIgnore="true" 属性添加到该布局文件的根视图中,如:

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

3. 使用

当你工程 Gradle 中配置启用 View binding 后,在工程编译阶段就会为每个布局文件生成对应的绑定类,其中类的名称规则是:XML 文件的名称转换为 Pascal 命名规则的大小写形式,并在末尾添加“Binding”。例如有一个名为 result_profile.xml 的布局文件,其中包含以下内容:

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

所生成的绑定类的名称就是 ResultProfileBinding。此类有两个字段:一个是名为 myName  的  TextView,另一个是名为 myButton 的 Button。因为布局中的 ImageView 没有 ID,所以类中没有对其的引用。

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

3.1. 在 Activity 中使用 View binding

在 Activity 的 onCreate 方法中,可以执行以下代码来绑定 Activity 和布局文件,以及获取布局文件中的 View 对象:

private lateinit var binding: ResultProfileBinding

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

    binding.myName.text = “Hello world!”
    binding.myButton.setOnClickListener {
       // TODO…
    }
}

说明:

  1. 绑定类中的静态 inflate() 方法用于创建该绑定类的实例以供 Activity 使用。
  2. 通过调用 getRoot() 方法获取对根视图的引用。
  3. 将根视图传递给 setContentView(),使其成为屏幕上的Activity 的View。

3.2. 在 Fragment 中使用View binding

若要在 Fragment 中使用绑定类,可在其 onCreateView 方法中执行以下代码:

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
}

说明:

  1. 跟 Activity 一样,使用了绑定类的静态 inflate() 方法来创建绑定类的实例,不同的是此处方法是三个参数的重载版本。
  2. 也是通过调用 getRoot() 方法获取对根视图的引用。
  3. onCreateView() 方法返回根视图对象,使其成为屏幕上的Activity 的 View。
  4. 注意在 onDestroyView 方法中记得要将绑定类置空。

3.3. 不同配置布局类型处理

如果你的工程中存在多种配置声明View时,有时可能会存在根据特定布局使用不同类型的View 的场景,例如:

# in res/layout/example.xml

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

# in res/layout-land/example.xml

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

在此情况下,你可能希望生成的 userBio 字段是 TextView 类型,因为TextView 也是 EditText 的父类,但是因为View binding 在生成代码时是无法在特殊多种配置情况下去验证布局 View 的类型,所以这里就只能默认生成了View 类型的 userBio 字段。然而在后面代码中使用该字段时就需要使用binding.userBio as TextView 来对字段进行转换。

针对这种特殊情况,View binding 支持 tools:viewBindingType 属性,可告知编译器在生成的代码中使用什么类型。在前面的示例中,可以使用此属性让编译器将字段生成为 TextView,例如:

# in res/layout/example.xml

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

# in res/layout-land/example.xml 

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

注意:

虽然通过 tools:viewBindingType 属性可在 View binding 在生成代码时指定字段类型,但是其内部是不存在类型校验逻辑的。为避免编译时和运行时错误,该值必须满足以下条件:

  1. 该值必须是继承自 android.view.View 的类。
  2. 该值必须是放置它的代码的父类。若上述示例中将 EditText 中的 tools:viewBindingType 设为 Button 是会产生错误的。
  3. 最终类型必须在所有配置中一致地解析。

4. 总结

根据 Android 官方开发者文档,View Binding 是官方推荐的视图绑定方案。它提供了一种更安全、更高效的方式进行视图绑定,可以减少开发者的工作量,提高代码的可维护性和性能,同时降低潜在的运行时错误风险。因此,如果你正在开发新的 Android 项目,View Binding 是一个很好的选择。

更多详细的 View Binding 介绍,请访问Android 开发者官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值