从 Android Studio 3.6 开始,视图绑定可能通过生成绑定对象来代替 findViewById,从而能够帮您简化代码、移除 bug,并且从 findViewById 的模版代码中解脱进去。
本文梗概
- 在 build.gradle 中就能够方便快捷地开启视图绑定且毋庸额定引入依赖库
- 视图绑定会为 Module 中的每一个布局文件生成一个绑定对象
(activity_awesome.xml
→ ActivityAwesomeBinding.java
)
- 布局文件中每一个带有 id 的视图都会在绑定对象中有一个对应的属性,这个属性将领有正确的类型,并且空平安
- 视图绑定完满反对 Java 和 Kotlin 编程语言
更多具体内容能够从视频:应用视图绑定代替 findViewById 中获取。
在 build.gradle 中开启视图绑定
开启视图绑定毋庸引入额定依赖,从 Android Studio 3.6 开始,视图绑定将会内建于 Android Gradle 插件中。须要关上视图绑定的话,只须要在 build.gradle 文件中配置 viewBinding 选项:
// 须要 Android Gradle Plugin 3.6.0
android {
viewBinding {enabled = true}
}
在 Android Studio 4.0 中,viewBinding 变成属性被整合到了 buildFeatures 选项中,所以配置要改成:
// 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 中应用视图绑定
应用视图绑定时,无须再调用 findViewById
办法,只有间接调用绑定对象中的对应属性即可。
布局的根视图(无论有没有 id)都会主动生成一个名为 root
的属性。在 Activity
的 onCreate
办法中,要将 root
传入 setContentView
办法,从而让 Activity
能够应用绑定对象中的布局。
一个常见的谬误用法是: 在开启了视图绑定的同时,仍然在 setContentView(…) 中传入布局的 id 而不是绑定对象。这将造成同一布局被填充两次,同时监听器也会被增加到谬误的布局对象中。
解决方案: 在 Activity 中应用视图绑定时,肯定要将绑定对象的 root 属性传入 setContentView() 办法中。
应用绑定对象编写安全性更佳的代码
findViewById
是许多用户可见 bug 的起源: 咱们很容易传入一个布局中基本不存在的 id,从而导致空指针异样而解体;因为此办法类型不平安,也很容易使人写出像 findViewById<TextView>(R.id.image)
这样的,导致类型转换谬误的代码。为了解决这些问题,视图绑定把 findViewById 替换成了更加简洁和平安的实现。
视图绑定有上面两个个性:
- 类型平安: 因为视图绑定总是会基于布局中的视图生成类型正确的属性。所以如果您在布局中放入了一个
TextView
,视图绑定就会裸露一个TextView
类型的属性给您。 - 空平安: 视图绑定会检测某个视图是不是只在一些配置下存在,并根据后果生成带有
@Nullable
注解的属性。所以即便在多种配置下定义的布局文件,视图绑定仍然可能保障空平安。
因为生成的绑定类是一般的 Java 类,并且其中增加了 Kotlin 敌对的注解,所以 Java 和 Kotlin 都能够应用视图绑定。
视图绑定生成的代码是怎么的
如前文所说,视图绑定会生成一个蕴含代替 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;
△ 视图绑定生成的属性。能够看到它们都是类型平安以及空平安的
视图绑定会依据每个领有 id 的视图生成类型正确的属性。他也会为根布局生成 rootView 属性并通过 getRoot 裸露给您。视图绑定没有增加任何额定的逻辑,他只是把视图属性裸露给您,从而帮您在不应用 findViewById 的状况下也能调用它们。这样一来便保障了生成文件简洁性(当然也防止了拖慢构建速度)。
如果您正在应用 Kotlin,视图绑定的生成类也曾经对互操作进行了优化。通过 @Nullable
和 @NonNull
注解的应用,Kolin 能够正确的将属性裸露为空平安类型。如果想要理解更多对于两种语言的互操作问题,请查阅文档: 在 Kotlin 中调用 Java。
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);
}
视图绑定会生成 inflate 办法作为生成一个绑定对象实例的次要形式。在 ActivityAwesomeBinding.java 中,视图绑定生成了一个只有一个参数的 inflate 办法,该办法通过将 parent 设定为空值来指定以后视图不会绑定到父视图中;视图绑定也裸露了一个有三个参数的 inflate 办法,来让您在须要的时候传入 parent 和 attachToParent 参数。
真正神奇的中央是 bind 办法的调用。这里会填充视图并绑定所有的属性,同时做一些谬误检测并生成清晰的谬误提醒。
@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 办法的简化版本
bind 是绑定对象中最简单的一个办法,它通过调用 findViewById 来绑定每个视图。既然编译器能够通过 XML 布局文件晓得每个属性的类型和为空的可能性,那他就能够平安的调用 findViewById。
请留神,视图绑定生成的真正的 bind 办法要来的更长,并且其中应用了一个标记 break 语句来优化字节码,您能够查看 Jake Wharton 撰写的这篇文章 来理解更多优化无关的内容。在每个绑定对象中,都会裸露三个静态方法来创立绑定对象实例,上面是每个办法应用场景的简要阐明:
- 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 标签的示例
留神: include 标签下有一个 id。
在应用引入布局的时候,视图绑定会创立一个被引入布局绑定对象的援用。留神 include> 标签有一个 id: android:id=”@+id/includes”。这里的逻辑跟应用一般视图一样,include 标签也须要有一个 id 能力在绑定对象中生成对应的属性。
include 标签必须有一个 id,能力生成对应的属性。
public final class ActivityAwesomeBinding implements ViewBinding {
...
@NonNull
public final IncludedButtonsBinding includes;
视图绑定会在 ActivityAwesomeBinding 中生成一个 IncludedButtonsBinding 的援用。
联合数据绑定来应用视图绑定
视图绑定只是 findViewById 的取代计划,如果您心愿在 XML 中主动绑定视图,能够应用 数据绑定 库。数据绑定和视图绑定能够生成同样的组件,它们能够同时工作。
在两者都被开启时,应用 <layout> 标签的布局会由数据绑定来生成绑定对象;而其余的布局则由视图绑定生成绑定对象。
您能够在同一 Module 中同时应用数据绑定和视图绑定。
咱们之所以开发视图绑定作为数据绑定的补充,是因为许多开发者反映说,心愿有一个轻量的解决方案,能在数据绑定之外代替 findViewById——视图绑定提供的正是这一性能。
视图绑定比照 Kotlin 合成办法与 ButterKnife
对于视图绑定,一个最常见的问题是: “ 我是否应该用视图绑定代替 Kotlin 合成办法或 ButterKnife ? ” 二者都是目前非常胜利的组件库,有许多利用应用它们解决 findViewById 的问题。
对于大多数利用来说,咱们举荐尝试应用视图绑定来代替这两个库,因为视图绑定能够提供更加平安和精确的视图映射形式。
上图为比照视图绑定、ButterKnife 和 Kotlin 合成办法的性能。
尽管 ButterKnife 会在运行时校验可空与不可空,然而编译器并不会查看您匹配的视图是否在存在于您的布局之中。
为了安全性与更简洁代码,咱们举荐尝试应用视图绑定。
点击这里理解更多无关视图绑定的信息。