美文网首页Android Zone
Android viewBinding使用简介

Android viewBinding使用简介

作者: 翻译不了的声响 | 来源:发表于2020-09-26 09:54 被阅读0次

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.ViewHolderonCreateViewHolder()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;
        }
    }

}

相关文章

网友评论

    本文标题:Android viewBinding使用简介

    本文链接:https://www.haomeiwen.com/subject/fzfzqktx.html