从BaseRecyclerViewAdapterHelper与ViewBinding的坑里爬出:封装之旅
2023-11-03 16:03:52
在开发中,优化RecyclerView的适配器是提高列表性能的关键,而BaseRecyclerViewAdapterHelper (BRVAH)无疑是Java开发中的佼佼者。ViewBinding 则进一步提升了代码的可读性,为开发者带来福音。然而,将两者结合使用时,却暗藏着诸多陷阱。本文将基于我自己的亲身经历,带你踏上这趟爬坑之旅,避免你掉入同样的泥潭。
踩坑第一步:简单的结合
乍一看,BRVAH与ViewBinding的结合似乎轻而易举:
// onBindViewHolder 中
@Override
public void onBindViewHolder(VBViewHo holder, int position) {
T data = getData(position);
holder.tvTitle.setText(data.title);
}
但实际运行后,却出现了崩溃:java.lang.ClassCastException: com.example.viewbinding.VBViewHo cannot be cast to com.chad.library.adapter.base.BaseViewHolder
。
踩坑第二步:设置EmptyView
为了处理空列表的场景,我们尝试设置一个EmptyView:
adapter.setEmptyView(R.layout.empty_view);
然而,在Logcat中发现了一个BRVAH内部的异常:
E/BRVAH: onBindViewHolder is not called when add or set empty view
这是因为BRVAH在设置EmptyView时,会调用自己的onBindViewHolder
方法,而我们重写的onBindViewHolder
却没有处理EmptyView的情况,导致了异常。
踩坑第三步:重写RecyclerView的onBindViewHolder
为了解决BRVAH中onBindViewHolder
方法不处理EmptyView的问题,我们尝试直接重写RecyclerView的onBindViewHolder
方法:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof VBViewHo) {
VBViewHo vbHolder = (VBViewHo) holder;
T data = getData(position);
vbHolder.tvTitle.setText(data.title);
} else {
// 处理EmptyView
}
}
然而,这一次又出现了崩溃:java.lang.IllegalStateException: Can't call getViewHolder(), can only call it after RecyclerView has been bound to an adapter
。
这是因为RecyclerView的onBindViewHolder
方法不能直接被调用,必须在RecyclerView绑定适配器之后才能使用。
最终解决方案:封装ViewBinding的BaseViewHolder
经过以上种种曲折,我们终于找到了最终的解决方案:封装一个集成了ViewBinding的BaseViewHolder。
public class VBViewHolder<T extends ViewBinding> extends BaseViewHolder {
private T binding;
public VBViewHolder(View view) {
super(view);
binding = generateBinding(view);
}
public T getBinding() {
return binding;
}
// 自动生成ViewBinding实例
private T generateBinding(View view) {
Class<?> bindingClass = null;
try {
bindingClass = Class.forName(view.getClass().getName() + "Binding");
Method inflateMethod = bindingClass.getMethod("inflate", View.class);
return (T) inflateMethod.invoke(null, view);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
使用这个封装过的ViewHolder,我们就可以在BRVAH中直接使用ViewBinding了:
@Override
public void onBindViewHolder(VBViewHolder<T> holder, int position) {
T data = getData(position);
holder.getBinding().tvTitle.setText(data.title);
}
通过封装BaseViewHolder,我们不仅解决了BRVAH与ViewBinding结合的各种问题,而且使代码更加简洁和可维护。