返回

从BaseRecyclerViewAdapterHelper与ViewBinding的坑里爬出:封装之旅

Android

在开发中,优化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结合的各种问题,而且使代码更加简洁和可维护。

SEO优化