ViewBinding
视图绑定是按模块启用的。要在 模块,请在模块级别将 viewBinding 构建选项设置为 true build.gradle 文件,如以下示例所示:
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这个类有两个 字段:一个名为 name 的 TextView 和一个名为 button 的 Button。通过 布局中的 ImageView 没有 ID,因此没有在绑定类中的引用。
每个绑定类还包括一个getRoot()方法,为相应布局文件的根视图提供直接引用。在这个例子中,ResultProfileBinding类中的getRoot()方法返回LinearLayout根视图。
在Activity中使用绑定类
private ResultProfileBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ResultProfileBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
}
binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
viewModel.userClicked()
});
在Fragment中使用绑定类
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; //这里需要主动释放
}
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" />
在这种情况下,您可能希望生成的类公开字段 userBio 类型为 TextView,因为 TextView 是公共基类。由于 由于存在技术限制,视图绑定代码生成器无法确定这一点, 系统会改为生成 View 字段。这需要稍后通过 binding.userBio as TextView。
为了绕过此限制,视图绑定支持 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"/>
再举一个例子,假设您有两个布局,其中一个布局包含一个 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" />
在生成代码时,视图绑定无法验证此属性的值。接收者 避免编译时错误和运行时错误,该值必须符合以下要求 条件:
1)该值必须是从 android.view.View 继承的类。
2)该值必须是其所在的标记的超类。例如, 以下值无效:
<TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
<TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
3)最终类型必须在所有配置中以一致的方式解析。
与findViewById区别
1)空指针安全:由于视图绑定创建了对视图的直接引用,因此不存在由于无效视图ID而导致空指针异常的风险。此外,当视图只出现在布局的某些配置文件中时,绑定类中包含其引用的字段被标记为@Nullable。
2)类型安全:每个绑定类中的字段的类型与它们在XML文件中引用的视图相匹配。这意味着没有类强制转换异常的风险。
这些差异意味着布局和代码之间的不兼容性会导致构建在编译时而不是在运行时失败。
与Databinding区别
Viewbinding和databinding都会生成绑定类,您可以使用这些绑定类直接引用视图。然而,viewbinding旨在处理更简单的用例,并提供以下优于databinding的好处:
1)更快的编译速度:viewbinding不需要处理注解,因为编译速度更快;
2)使用更容易:viewbinding不需要特别标记的XML布局文件,因此在应用程序中采用它会更快。一旦你在模块中启用了viewbinding,它就会自动应用于该模块的所有布局。
viewbinding与databinding比较的缺点:
1)viewbinding不支持layout 变量和layout表达式,所以不能动态的在XML layouts文件中动态的生成内容;
2)viewbinding不支持双向的数据绑定;
由于这些考虑,在某些情况下,最好在项目中同时使用viewbinding和databinding。你可以在需要高级特性的布局中使用databinding,在不需要高级特性的布局中使用viewbinding。