返回

DataBind抛弃Adapter和ViewHolder,重新定义列表控件交互方式

Android

现在,在列表控件的使用上,一般都会采用Adapter加ViewHolder的方式,这种方式虽然相对于最初的列表控件使用有了极大的进步,但是仍然存在很多问题,比如:

  • ViewHolder生命周期跟Adapter不一致。
  • 多种Item布局需要新建多个ViewHolder。
  • 不易解耦。
  • 占用空间大。
  • 无法充分利用DataBinding。
  • 继承代价太大。

本文将抛弃Adapter和ViewHolder,重新定义列表控件交互方式,并基于DataBinding实现可扩展且解耦的列表控件解决方案。


ItemViewModel

类似于MVVM模式中ViewModel,这里将Item的layoutId当作Item的viewType,同时包含Item相关的数据,它扮演类似于ViewHolder的角色,因此将其命名为ItemViewModel。

class UserInfo {

  private String name;

  private int age;

  public UserInfo(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public int getLayoutId() {
    // 根据数据返回不同的layoutId
    if (age > 18) {
      return R.layout.item_adult;
    } else {
      return R.layout.item_child;
    }
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

}

DataBindingAdapter

DataBindingAdapter用于将ItemViewModel和layout进行绑定,这样就能在layout中直接使用ItemViewModel中的数据了。

class DataBindingAdapter {

  @BindingAdapter("android:layout")
  public static void setLayout(View view, int layoutId) {
    view.setTag(R.id.layoutId, layoutId);
  }

}

BaseRecyclerAdapter

BaseRecyclerAdapter是一个通用的RecyclerAdapter,它实现了基本的Adapter功能,如数据绑定、Item点击事件等。

class BaseRecyclerAdapter extends RecyclerView.Adapter {

  private List<ItemViewModel> items;

  public BaseRecyclerAdapter(List<ItemViewModel> items) {
    this.items = items;
  }

  @Override
  public int getItemViewType(int position) {
    return items.get(position).getLayoutId();
  }

  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
    return new BindingViewHolder(view);
  }

  @Override
  public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    ItemViewModel item = items.get(position);
    DataBindingUtil.bind(holder.itemView).setVariable(BR.item, item);
    holder.itemView.setOnClickListener(v -> {
      // Item点击事件
    });
  }

  @Override
  public int getItemCount() {
    return items.size();
  }

}

使用方式

List<UserInfo> users = new ArrayList<>();
// 省略数据初始化代码

RecyclerView recyclerView = findViewById(R.id.recyclerView);
BaseRecyclerAdapter adapter = new BaseRecyclerAdapter(users);
recyclerView.setAdapter(adapter);

优势

  • 生命周期一致。
  • 无需创建多个ViewHolder。
  • 易于解耦。
  • 占用空间小。
  • 充分利用DataBinding。
  • 继承代价小。

总结

本文抛弃Adapter和ViewHolder,重新定义列表控件交互方式,并基于DataBinding实现可扩展且解耦的列表控件解决方案。这种方式具有生命周期一致、无需创建多个ViewHolder、易于解耦、占用空间小、充分利用DataBinding、继承代价小的优点,在实际项目中具有很强的适用性。