解决notifyItemChanged刷新图片闪烁问题

因为项目中会经常使用到RecyclerView,因此,就会写许多的Adapter,这些Adapter写的多了,就发现有很多有大量重复的代码,有的甚至一模一样,因此就想到应该对Adapter做一些封装,将重复公用的部分封装到一个基类里,而让继承这个基类的子Adapter只关心控件数据的更新工作,其他的像绑定,点击事件,对某个Item 的操作都放在基类里,这样一来就能省不少事。具体代码看起来很简单,但是自己写的时候还是花了一上午的时候考虑了一些细节的问题,下面是代码,就一个抽象类:


public abstract class BaseRecyclerViewAdapter<E, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
    protected Context mContext;
    protected List<E> mData = new ArrayList<>();
    protected OnItemClickListener<E> mOnItemClickListener;

    public BaseRecyclerViewAdapter(Context context) {
        mContext = context;
    }

    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(findResById(), parent, false);
        return createVH(view);
    }

    /**
     * 添加数据,在原有数据的末尾继续添加新的数据(加载更多/下拉刷新)
     *
     * @param data     待添加的数据
     * @param isDelete 是否删除原有的数据
     */
    public void updateData(List<E> data, boolean isDelete) {
        if (data == null)
            return;
        int oldSize = mData.size();
        int newSize = data.size();
        if (isDelete) { //mData清空的时候要通知adapter也将数据清空,否则在更新数据的时候会报错
            mData.clear();
            notifyItemRangeRemoved(0, oldSize);
        }
        mData.addAll(data);
        notifyItemRangeInserted(oldSize , oldSize + newSize);
    }

    /**
     * 删除列表中指定位置的item
     *
     * @param position 指定删除的位置
     */
    public void removeItem(int position) {
        if (mData.size() == 0)
            return;
        if (position >= mData.size())
            return;
        mData.remove(position);
        notifyItemRemoved(position);
        //删除一个item后,通知adapter去刷新position否则会出现位置错乱
        notifyItemRangeChanged(0, mData.size());
    }

    /**
     * 更新列表指定位置的数据
     *
     * @param position 数据更新的位置
     * @param data     需要更新的数据
     * @param obj      不为空时将调用{@link #updateView(RecyclerView.ViewHolder, int, List)}方法更新指定的控件,
     *                 否则将更新整个item,此时会有闪烁的问题
     */
    public void updateItem(int position, E data, @Nullable Object obj) {
        if (mData.size() == 0)
            return;
        if (position > mData.size())
            return;
        if (position < mData.size()) {
            mData.remove(position);
        }
        mData.add(position, data);
        notifyItemChanged(position, obj);
    }


    //重写此方法,解决更新单个item时闪烁的问题
    @Override
    public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {
            onBindViewHolder(holder, position);
        } else { //更新控件
            updateView(holder, position, payloads);
        }
    }

    protected void updateView(VH holder, int position, @NonNull List<Object> payloads) {

    }

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

    protected E getItemByPosition(int position) {
        return mData.get(position);
    }

    protected abstract VH createVH(View view);

    protected abstract int findResById();


    public void setOnItemClickListener(OnItemClickListener<E> listener) {
        mOnItemClickListener = listener;
    }

    /**
     * RecyclerView的item点击事件接口
     */
    public interface OnItemClickListener<E> {
        void onItemClick(View view, int position, E data);
    }

}

这个是基类的封装,基本满足了目前的需求,然后是子类继承使用这个基类,还是直接看代码

public class DataAdapter extends BaseRecyclerViewAdapter<String, DataAdapter.DataViewHolder> {


    public DataAdapter(Context context) {
        super(context);
    }

    @Override
    protected DataViewHolder createVH(View view) {
        return new DataViewHolder(view);
    }

    @Override
    protected int findResById() {
        return R.layout.item;
    }

    @Override
    public void onBindViewHolder(@NonNull DataViewHolder holder, int position) {
        if (position % 2 == 0) {
            holder.mTvItemNameView.setBackgroundColor(mContext.getResources().getColor(R.color.colorAccent));
        } else {
            holder.mTvItemNameView.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimary));
        }
        holder.mTvItemNameView.setText(getItemByPosition(position));
    }

    @Override
    protected void updateView(DataViewHolder holder, int position, @NonNull List<Object> payloads) {
        holder.mTvItemNameView.setText(getItemByPosition(position));
    }

    public class DataViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView mTvItemNameView;

        public DataViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            mTvItemNameView = itemView.findViewById(R.id.tv_item_name);
        }

        @Override
        public void onClick(View v) {
            int position = getAdapterPosition();
            if (mOnItemClickListener != null)
                mOnItemClickListener.onItemClick(v, position, getItemByPosition(position));
        }
    }
}

子类里只做一件事就是更新控件的数据,其他的都交给父类去做,这样简单的封装一下,代码看起来干净了不少,也不用每个adapter都做很多重复的工作了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容