以下文章来源于谷歌开发者 ,作者Android
Google 中国官方账号。汇集 Android, Flutter, Chrome OS, Chrome/web, AI 等开发技术,以及 Google Play 平台出海相关信息。
从 Android Studio 3.6 开始,视图绑定能够通过生成绑定对象来替代 findViewById,从而可以帮您简化代码、移除 bug,并且从 findViewById 的模版代码中解脱出来。
在 build.gradle 中就可以方便快捷地开启视图绑定且无须额外引入依赖库
视图绑定会为 Module 中的每一个布局文件生成一个绑定对象
(activity_awesome.xml → ActivityAwesomeBinding.java)
布局文件中每一个带有 id 的视图都会在绑定对象中有一个对应的属性,这个属性将拥有正确的类型,并且空安全
视图绑定完美支持 Java 和 Kotlin 编程语言
腾讯视频链接
https://v.qq.com/x/page/h0931mdo8ly.html
Bilibili 视频链接
https://www.bilibili.com/video/av95393509/
在 build.gradle 中开启视图绑定
// 需要 Android Gradle Plugin 3.6.0
android {
viewBinding {
enabled = true
}
}
// Android Studio 4.0
android {
buildFeatures {
viewBinding = true
}
}
配置完成后,视图绑定就会为所有布局文件自动生成对应的绑定类。无须修改原有布局的 XML 文件,视图绑定将根据您现有的布局自动完成所有工作。
视图绑定将会根据现有的 XML 文件,为 Module 内所有的布局文件生成绑定对象。
您可以在任何需要填充布局的地方使用绑定对象,比如 Fragment、Activity、甚至是 RecyclerView Adapter(或者说是 ViewHolder 中)。
在 Activity 中使用视图绑定
假如您有一个布局文件名叫 activity_awesome.xml,其中包含了一个按钮和两个文本视图。视图绑定会为这个布局生成一个名叫 ActivityAwesomeBinding 的类,布局文件中所有拥有 id 的视图,都会在这个类中有一个对应的属性:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityAwesomeBinding.inflate(layoutInflater)
binding.title.text = "Hello"
binding.subtext.text = "Concise, safe code"
binding.button.setOnClickListener { /* ... */ }
setContentView(binding.root)
}
△ 在 Activity 中使用视图绑定
一个常见的错误用法是: 在开启了视图绑定的同时,依然在 setContentView(...) 中传入布局的 id 而不是绑定对象。这将造成同一布局被填充两次,同时监听器也会被添加到错误的布局对象中。
解决方案: 在 Activity 中使用视图绑定时,一定要将绑定对象的 root 属性传入 setContentView() 方法中。
使用绑定对象编写安全性更佳的代码
视图绑定生成的代码是怎样的
如前文所说,视图绑定会生成一个包含替代 findViewById 功能的 Java 类。它会为 Module 下的每一个布局的 XML 文件生成一个对应的绑定对象,并根据源文件为其命名,比如 activity_awesome.xml 对应的绑定对象为 ActivityAwesomeBinding.java。
生成代码的逻辑被优化为,当您在 Android Studio 中编辑 XML 布局文件时,只会更新所修改布局对应的绑定对象。同时这些工作会在内存中运行,从而使这个过程可以迅速完成。这意味着您的修改会立即反映在绑定对象中,而无须等待或者重新构建工程。
Android Studio 被优化为可以在您编辑过 XML 布局文件后立即更新绑定对象。
让我们通过一个示例 XML 布局所生成的代码,来了解一下视图绑定究竟生成了什么。
public final class ActivityAwesomeBinding implements ViewBinding {
@NonNull
private final ConstraintLayout rootView;
@NonNull
public final Button button;
@NonNull
public final TextView subtext;
@NonNull
public final TextView title;
△ 视图绑定生成的属性。可以看到它们都是类型安全以及空安全的
private ActivityAwesomeBinding(@NonNull ConstraintLayout rootView, @NonNull Button button,
@NonNull TextView subtext, @NonNull TextView title) { … }
@NonNull
public static ActivityAwesomeBinding inflate(@NonNull LayoutInflater inflater) {
/* 编辑过: 移除了重载方法 inflate(inflater, parent, attachToParent) 的调用*/
View root = inflater.inflate(R.layout.activity_awesome, null, false);
return bind(root);
}
@NonNull
public static ActivityAwesomeBinding bind(@NonNull View rootView) {
/* 编辑: 简化代码 – 真实情况下生成的代码是一个优化过的版本 */
Button button = rootView.findViewById(R.id.button);
TextView subtext = rootView.findViewById(R.id.subtext);
TextView title = rootView.findViewById(R.id.title);
if (button != null && subtext != null && title != null) {
return new ActivityAwesomeBinding((ConstraintLayout) rootView, button, subtext, title);
}
throw new NullPointerException("Missing required view […]");
}
bind 是绑定对象中最复杂的一个方法,它通过调用 findViewById 来绑定每个视图。既然编译器可以通过 XML 布局文件知道每个属性的类型和为空的可能性,那他就可以安全的调用 findViewById。
inflate(inflater) -- 在例如 Activity onCreate 方法里,这类没有父视图需要被传入的场合使用
inflate(inflater, parent, attachToParent) -- 在 Fragment 或 RecyclerView Adapter (或者说 ViewHolder 中) ,这类您需要传递父级 ViewGroup 给绑定对象时使用。
bind(rootView) -- 在您已经获得对应视图,并且只想通过视图绑定来避免使用 findViewById 时使用。这个方法在使用视图绑定改造和重构现有代码时非常有用。
对使用 <include> 标签引入的布局会发生什么影响
前面已经讲过,视图绑定会为 Module 下的每一个布局文件生成一个绑定对象,这个说法在布局文件被另一个布局文件使用 <include> 引入时依然适用。
<!-- activity_awesome.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
<include android:id="@+id/includes" layout="@layout/included_buttons"
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- included_buttons.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
<Button android:id="@+id/include_me" />
</androidx.constraintlayout.widget.ConstraintLayout>
注意: include 标签下有一个 id。
include 标签必须有一个 id,才能生成对应的属性。
public final class ActivityAwesomeBinding implements ViewBinding {
...
@NonNull
public final IncludedButtonsBinding includes;
结合数据绑定来使用视图绑定
您可以在同一 Module 中同时使用数据绑定和视图绑定。
我们之所以开发视图绑定作为数据绑定的补充,是因为许多开发者反映说,希望有一个轻量的解决方案,能在数据绑定之外替代 findViewById——视图绑定提供的正是这一功能。
视图绑定对比 Kotlin 合成方法与 ButterKnife
△ 视图绑定空安全、只引用当前布局中的视图、支持 Java 和 Kotlin,同时也更简洁
虽然 ButterKnife 会在运行时校验可空与不可空,但是编译器并不会检查您匹配的视图是否在存在于您的布局之中。
为了安全性与更简洁代码,我们推荐尝试使用视图绑定。
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!