viewBinding(视图绑定)通过视图绑定功能,可以更轻松地编写可与视图交互的代码。在模块配置文件中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。
1. 视图绑定对比
与使用 findViewById 相比,视图绑定具有一些很显著的优点:
-
Null 安全:由于视图绑定会创建对视图的直接引用,所以不会因视图 ID 无效而引发 Null 指针异常的风险。此外,如果视图仅出现在布局的某些配置中,则绑定类中包含其引用的字段会使用
@Nullable
标记; -
类型安全:每个绑定类中的字段均具有与它们在 XML 文件中引用的视图相匹配的类型,这样就不会发生类转换异常的风险。
这些差异意味着布局和代码之间的不兼容将会导致构建在编译时(而非运行时)失败。
2. 视图绑定配置
视图绑定在需要在 Android Studio 3.6 及更高版本中才能使用。
视图绑定功能可按模块启用,在需要的模块build.gradle
文件中添加viewBinding
元素启用视图绑定:
android {
...
viewBinding {
enabled = true
}
}
如果在生成绑定类时忽略某个布局文件,可以在相应布局文件的根视图中添加tools:viewBindingIgnore="true"
属性即可:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:viewBindingIgnore="true">
...
</RelativeLayout>
3. 视图绑定用法
为某个模块启用视图绑定功能后,系统会为该模块中包含的每个 XML 布局文件生成一个绑定类。每个绑定类均包含对根视图以及具有 ID 的所有视图的引用。系统会在项目模块下的build/generated/data_binding_base_class_sources_out/debug/out/包名/databinding
目录下,将 XML 文件的名称转换为驼峰式大小写方式生成绑定类的名称,并在末尾添加“Binding”。
例如一个布局文件的名称为activity_main.xml
:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:id="@+id/btn_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_bg" />
</LinearLayout>
所生成的绑定类的名称就为:ActivityMainBinding,生成类中包含:布局中 id 的View
、为相应布局文件的根视图提供直接引用的getRoot()
方法、创建绑定类的实例提供引用的静态inflate()
方法。
-
在 Activity 中使用视图绑定
如果在 Activity中使用绑定类的实例,需要在 Activity的onCreate()
方法中执行以下步骤:
1)调用生成的绑定类中包含的静态inflate()
方法,此操作会创建该绑定类的实例以供 Activity使用;
2)通过调用getRoot()
方法获取对根视图的引用;
3)将根视图传递到setContentView()
方法中,使其成为屏幕上的视图。
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
}
绑定类配置完,就可以使用该绑定类的实例来引用xml布局中的视图:
binding.tvName.setText("Activity");
binding.btnButton.setOnClickListener(new View.OnClickListener() {
finish();
});
-
在 Fragment 中使用视图绑定
如果在 Fragment 中使用绑定类的实例,需要在 Fragment的onCreateView()
方法中执行以下步骤:
1)调用生成的绑定类中包含的静态inflate()
方法,此操作会创建该绑定类的实例以供 Fragment 使用;
2)通过调用getRoot()
方法获取对根视图的引用;
3)从onCreateView()
方法返回根视图,使其成为屏幕上的视图。
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();
binding = null;
}
绑定类配置完,就可以使用该绑定类的实例来引用xml布局中的视图:
binding.tvName.setText("Fragment");
binding.btnButton.setOnClickListener(new View.OnClickListener() {
finish();
});
-
在 Adapter中使用视图绑定
1)在继承RecyclerView.Adapter的类中使用
如果在继承 RecyclerView.Adapter类中使用绑定类的实例,需要在 RecyclerView.Adapter中的几个方法RecyclerView.ViewHolder
、onCreateViewHolder()
、onBindViewHolder()
方法中执行以下步骤:
(1) 自定义内部类ViewHolder
并继承RecyclerView.ViewHolder
类,声明绑定类对象,通过调用getRoot()
方法获取根视图传入View参数;
(2) 在onCreateViewHolder()
方法中,调用生成的绑定类中包含的静态inflate()
方法创建该绑定类的实例并传入自定义ViewHolder
类中,最后返回自定义ViewHolder
的实例;
(3) 在onBindViewHolder()
方法中,通过自定义的ViewHolder
类中的绑定类对象获取布局中的视图,并赋值展示。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
...
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemTestBinding binding = ItemTestBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull final MyAdapter.ViewHolder holder, final int position) {
holder.binding.tvTitle.setText("测试内容");
}
public class ViewHolder extends RecyclerView.ViewHolder{
ItemTestBinding binding;
public ViewHolder(ItemTestBinding itemBinding) {
super(itemBinding.getRoot());
binding = itemBinding;
}
}
}
2)在继承BaseAdapter的类中使用
如果在继承 BaseAdapter类中使用绑定类的实例,需要在 BaseAdapter中的getView()
方法中执行以下步骤:
(1) 创建一个ViewHolder
缓存类,声明绑定类对象;
(2) 在getView()
方法中,没有缓存时,调用生成的绑定类中包含的静态inflate()
方法创建该绑定类的实例并传入创建的ViewHolder
类中,通过调用getRoot()
方法获取根视图,然后调用convertView的setTag()
方法,传入ViewHolder对象,建立起了convertView与ViewHolder之间的关系;如果有缓存时,调用convertView的getTag()
取得关联的对象,将返回结果赋给ViewHolder引用;
(3) 通过创建的ViewHolder
类中的绑定类对象获取布局中的视图,并赋值展示。
public class MyAdapter extends BaseAdapter {
...
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
ItemTestBinding binding = ItemTestBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
holder = new ViewHolder(binding);
convertView = binding.getRoot();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.binding.tvTitle.setText("测试内容");
return convertView;
}
class ViewHolder {
public ItemTestBinding binding;
public ViewHolder(ItemTestBinding itemBinding) {
binding = itemBinding;
}
}
}
网友评论