最近有点空闲 将最近使用的DiffUtil局部刷新进行了一个整理
封装了一个BaseDiffAdapter,一个类搞定
一些坑基本也踩完了,什么图片闪烁、item闪烁、数据源刷新view不刷新等等

放段代码 欢迎拍砖

package com.example.basediffadapter;import android.app.Activity;import android.os.Handler;import android.os.Looper;import android.support.annotation.LayoutRes;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v7.util.DiffUtil;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;/** * 高级自带Diff局部刷新功能Adapter * 在对List 进行操作完后 请勿使用notifyDataSetChanged()方法 * 严格调用 setData addData removeData getData updateData 等方法 * Project: ProjectBaseDiffAdapter * Author: LiShen * Time: 2018/9/11 15:16 */public abstract class BaseDiffAdapter<T extends BaseDiffBean, V extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<V> {    private Activity activity;    private Class<T> tClass;    private Handler mainHandler = new Handler(Looper.getMainLooper());    private List<T> oldData = new ArrayList<>();// 用于新旧对比的旧数据    private List<T> data = new ArrayList<>();// 当前数据    private OnItemClickListener<T> onItemClickListener;    private boolean canNotRefresh = false;    public BaseDiffAdapter(Activity activity, Class<T> tClass) {        this.activity = activity;        this.tClass = tClass;    }    /**     * 正常数据绑定     *     * @param holder     * @param position     */    public abstract void bindViewAndData(V holder, int position);    /**     * 局部数据绑定     *     * @param holder     * @param position     * @param newBean     */    public abstract void partBindViewAndData(V holder, int position, T newBean);    @Override    public abstract V onCreateViewHolder(ViewGroup parent, int viewType);    @Override    public final void onBindViewHolder(V holder, int position) {        bindViewAndData(holder, position);    }    @Override    public final void onBindViewHolder(@NonNull V holder, int position, @NonNull List<Object> payloads) {        if (payloads.isEmpty()) {            onBindViewHolder(holder, position);        } else {            partBindViewAndData(holder, position, (T) payloads.get(0));        }    }    @Override    public int getItemCount() {        return data.size();    }    public void setData(List<T> outData) {        setData(outData, null);    }    /**     * 更新数据 核心方法 每次传入新数据时 将列表 data 和 oldData 用      * DiffUtil进行对比(子线程)再将结果 dispatchUpdatesTo 到     * adapter 上 进行界面刷新 (主线程)最后 再将 data 序列化成 新的     * oldData (子线程)以备下次对比     *      *     * @param outData     * @param callback     */    public void setData(List<T> outData, final OnSetDataFinishCallback callback) {        if (canNotRefresh) {            return;        }        canNotRefresh = true;        data.clear();        if (outData != null) {            data.addAll(outData);        }        WorkThreadHelper.get().execute(new Runnable() {            @Override            public void run() {                // 子线程计算差异                final DiffUtil.DiffResult result = DiffUtil.calculateDiff(                        new BaseDiffCallback(                                new ArrayList<>(oldData),                                new ArrayList<>(data)));                mainHandler.post(new Runnable() {                    @Override                    public void run() {                        // dispatch 到 adapter 进行界面刷新                        result.dispatchUpdatesTo(BaseDiffAdapter.this);                    }                });                oldData.clear();                for (T t : data) {                    // 子线程序列化生成新列表                    oldData.add(JSON.parseObject(JSON.toJSONString(t), tClass));                }                canNotRefresh = false;                // 如果有回调                if (callback != null) {                    mainHandler.post(new Runnable() {                        @Override                        public void run() {                            callback.onFinish();                        }                    });                }            }        });    }    /**     * 加数据     *     * @param t     */    public void addData(T t) {        if (t != null) {            List<T> temp = new ArrayList<>(data);            temp.add(t);            setData(temp);        }    }    /**     * 加数据     *     * @param index     * @param t     */    public void addData(int index, T t) {        if (t != null) {            List<T> temp = new ArrayList<>(data);            temp.add(index, t);            setData(temp);        }    }    /**     * 加一批数据     *     * @param list     */    public void addData(List<T> list) {        if (list != null) {            List<T> temp = new ArrayList<>(data);            temp.addAll(list);            setData(temp);        }    }    /**     * 删数据     *     * @param position     */    public void removeData(int position) {        List<T> temp = new ArrayList<>(data);        temp.remove(position);        setData(temp);    }    /**     * 删数据     *     * @param id     */    public void removeData(String id) {        int flag = -1;        for (int i = 0; i < data.size(); i++) {            if (data.get(i).getDiffId().equals(id)) {                flag = i;                break;            }        }        if (flag >= 0) {            removeData(flag);        }    }    /**     * 删数据     *     * @param t     */    public void removeData(T t) {        List<T> temp = new ArrayList<>(data);        temp.remove(t);        setData(temp);    }    /**     * 清除     */    public void clearData() {        List<T> temp = new ArrayList<>(data);        temp.clear();        setData(temp);    }    /**     * 修改完 {@link #data} 之后 调用此方法     */    public void notifyDataUpdated() {        setData(new ArrayList<>(getData()));    }    public List<T> getData() {        return data;    }    public T getItemData(int position) {        return data.get(position);    }    public View inflater(@LayoutRes int layoutId) {        return getActivity().getLayoutInflater().inflate(layoutId, null);    }    public Activity getActivity() {        return activity;    }    /**     * Item被点击了     *     * @param holder     * @return     */    public int onViewHolderItemClick(RecyclerView.ViewHolder holder) {        int position = holder.getLayoutPosition();        if (position >= 0 && position < getData().size()) {            if (getOnItemClickListener() != null) {                getOnItemClickListener().onItemClick(position, getItemData(position));            }        }        return position;    }    public interface OnItemClickListener<T> {        void onItemClick(int position, T t);    }    public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {        this.onItemClickListener = onItemClickListener;    }    public OnItemClickListener<T> getOnItemClickListener() {        return onItemClickListener;    }    private class BaseDiffCallback extends DiffUtil.Callback {        private List<T> oldList;        private List<T> newList;        private BaseDiffCallback(List<T> oldList, List<T> newList) {            this.oldList = oldList;            this.newList = newList;        }        @Override        public int getOldListSize() {            return oldList != null ? oldList.size() : 0;        }        @Override        public int getNewListSize() {            return newList != null ? newList.size() : 0;        }        @Override        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {            return oldList.get(oldItemPosition).getDiffId().equals(                    newList.get(newItemPosition).getDiffId());        }        @Override        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {            return oldList.get(oldItemPosition).getDiffContent().equals(                    newList.get(newItemPosition).getDiffContent());        }        @Nullable        @Override        public Object getChangePayload(int oldItemPosition, int newItemPosition) {            T newBean = newList.get(newItemPosition);            if (!areContentsTheSame(oldItemPosition, newItemPosition)) {                return newBean;            }            return null;        }    }    public interface OnSetDataFinishCallback {        void onFinish();    }}

使用:
先写一个实体类实现BaseDiffBean

public class DemoBean implements BaseDiffBean, Comparable<DemoBean> {    public int id;    @DrawableRes    public int icon;    public String content;    public void generateData() {        // 非核心代码 无视        id = DemoUtil.generateId();        icon = DemoUtil.generateRandomIcon();        content = DemoUtil.generateRandomString();    }    /**    * 这个方法是为了对比两个类 数据 是否一模一样    **/    @NonNull    @Override    public String getDiffContent() {        return "DemoBean{" +                "id=" + id +                ", icon=" + icon +                ", content='" + content + '\'' +                '}';    }    /**    * 对比两个对象是不是一个    **/    @NonNull    @Override    public String getDiffId() {        return String.valueOf(id);    }    // 非核心代码 无视    @Override    public int compareTo(DemoBean o) {        return (int) (this.id - o.id);    }}

再写个adapter继承BaseDiffAdapter

public class DemoAdapter extends BaseDiffAdapter<DemoBean, DemoAdapter.ViewHolder> {    public DemoAdapter(Activity activity, Class<DemoBean> demoBeanClass) {        super(activity, demoBeanClass);        setHasStableIds(true);    }    @Override    public void bindViewAndData(final ViewHolder holder, int position) {        Log.i("BaseDiffAdapter", "bindViewAndData: " + position);        // 正常数据绑定        DemoBean data = getItemData(position);        // 配合 setHasStableIds getItemId 防止 图片闪烁        Integer cache = (Integer) holder.ivItemDemo.getTag(R.id.ivItemDemo);        if (cache == null || cache != data.icon) {            holder.ivItemDemo.setImageResource(data.icon);            holder.ivItemDemo.setTag(R.id.ivItemDemo, data.icon);        }        holder.tvItemDemo.setText(data.content);        holder.tvItemDemoId.setText("ID: " + data.id);        holder.ivItemDemoDelete.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                int index = holder.getAdapterPosition();                removeData(index);// 删除数据            }        });    }    @Override    public void partBindViewAndData(ViewHolder holder, int position, DemoBean newBean) {        Log.d("BaseDiffAdapter", "partBindViewAndData: " + position);        // 局部数据刷新 业务中可能不会每个界面元素都会刷新        Integer cache = (Integer) holder.ivItemDemo.getTag(R.id.ivItemDemo);        if (cache == null || cache != newBean.icon) {            holder.ivItemDemo.setImageResource(newBean.icon);            holder.ivItemDemo.setTag(R.id.ivItemDemo, newBean.icon);        }        holder.tvItemDemo.setText(newBean.content);    }    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        return new ViewHolder(inflater(R.layout.item_demo));    }    @Override    public long getItemId(int position) {        return getItemData(position).id;    }    class ViewHolder extends RecyclerView.ViewHolder {        private ImageView ivItemDemo;        private ImageView ivItemDemoDelete;        private TextView tvItemDemo;        private TextView tvItemDemoId;        ViewHolder(@NonNull View itemView) {            super(itemView);            ivItemDemo = itemView.findViewById(R.id.ivItemDemo);            ivItemDemoDelete = itemView.findViewById(R.id.ivItemDemoDelete);            tvItemDemo = itemView.findViewById(R.id.tvItemDemo);            tvItemDemoId = itemView.findViewById(R.id.tvItemDemoId);        }    }}
    /**     * 增加数据     */    private void addData() {        DemoBean d = new DemoBean();        d.generateData();        demoAdapter.addData(0, d);// 增加数据 头部插入        // demoAdapter.addData(d);// 尾部插入        // 非核心代码        mainHandler.postDelayed(new Runnable() {            @Override            public void run() {                RecyclerView rvDemo = findViewById(R.id.rvDemo);                rvDemo.smoothScrollToPosition(0);            }        }, 100);    }    /**     * 随机改变某一项item的数据     */    private void refreshData() {        int max = demoAdapter.getItemCount();        if (max > 0) {            Random random = new Random();            int chosen = random.nextInt(max - 1);            // 更改数据            DemoBean itemData = demoAdapter.getItemData(chosen);            itemData.content = DemoUtil.generateRandomString();            itemData.icon = DemoUtil.generateRandomIcon();            // 重点!此处不能调用 notifyDataSetChanged            demoAdapter.notifyDataUpdated();        }    }

源码链接

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. Android(安卓)Room 增删改查 个人经验
  3. Android(安卓)自定义ContentProvider简单实例
  4. Android开发:使用AudioTrack播放PCM音频数据【附源码】
  5. Android(安卓)SQLiteOpenHelper
  6. Android获取assets文件夹中的数据并写入SD卡示例
  7. HttpClient 多线程
  8. Android(安卓)LiveData 使用详解
  9. android 圆形ListView实现,并附带圆角ImageView

随机推荐

  1. android开发之Launcher icon(启动图标)的设
  2. Android(安卓)4.1 Audio系统变化说明
  3. Android用surface直接显示yuv数据(一)
  4. 安卓开发者必备的5款App:终端模拟器、颜色
  5. 完整Android(安卓)CAN总线程序开发
  6. Android自定义星星评分控件
  7. 【Bugly干货分享】那些年我们用过的显示
  8. Android通过OkHttp框架上传照片到服务器
  9. SB程序媛学习笔记--Android(安卓)zxing实
  10. 大厂面试,居然还问这些问题!