Android中Volley缓存导致RecyclerView出现重复视图问题求助
解决Volley缓存软过期后RecyclerView重复数据的高效方案
你的问题根源在于Volley在缓存软过期时会触发两次onResponse回调:第一次返回本地缓存的数据,第二次返回网络请求获取的最新数据。而你的代码在每次回调时都直接将数据追加到listGrades中,没有清空旧数据,导致最终列表中同时存在缓存和新数据,出现重复。
之前的去重方案在大数据场景下开销高,其实我们可以从根源上避免重复,直接替换数据而非追加,具体方案如下:
1. 修复onResponse的核心处理逻辑
在处理响应数据前,先清空listGrades,再重新添加新数据。这样不管是缓存响应还是网络新响应,都会完全替换掉旧数据,从根本上杜绝重复:
@Override public void onResponse(JSONArray response) { // 关键:先清空列表,避免重复追加数据 listGrades.clear(); for (int i = 0; i < response.length(); i++) { try { Categories gradee = new Categories(); JSONObject json = response.getJSONObject(i); gradee.setImageUrl(json.getString(Config.TAG_G_IMAGE_URL)); gradee.setName(json.getString(Config.TAG_G_NAME)); listGrades.add(gradee); } catch (JSONException e) { e.printStackTrace(); } } progressBar.setVisibility(View.GONE); adapter.notifyDataSetChanged(); }
2. 移除后台线程中不安全的列表操作
你原来在parseNetworkResponse里的listGrades.clear();是错误的:parseNetworkResponse运行在Volley的后台线程中,直接操作UI线程维护的集合会引发线程安全问题,而且这个时机完全没必要。请删除这行代码,所有列表的修改都放在UI线程的onResponse中处理。
3. (可选)优化大数据场景下的RecyclerView更新效率
如果你的数据量很大,notifyDataSetChanged()会刷新整个列表,可能影响性能。可以改用DiffUtil来计算新旧数据的差异,只更新变化的项:
// 自定义DiffUtil回调类,用于判断数据差异 public class CategoriesDiffCallback extends DiffUtil.Callback { private List<Categories> oldList; private List<Categories> newList; public CategoriesDiffCallback(List<Categories> oldList, List<Categories> newList) { this.oldList = oldList; this.newList = newList; } @Override public int getOldListSize() { return oldList.size(); } @Override public int getNewListSize() { return newList.size(); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { // 根据数据的唯一标识判断是否为同一项(如果Categories有id字段,建议用id判断) return oldList.get(oldItemPosition).getName().equals(newList.get(newItemPosition).getName()); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { // 判断项的内容是否完全一致 Categories oldCat = oldList.get(oldItemPosition); Categories newCat = newList.get(newItemPosition); return oldCat.getImageUrl().equals(newCat.getImageUrl()) && oldCat.getName().equals(newCat.getName()); } } // 在onResponse中使用DiffUtil更新列表 @Override public void onResponse(JSONArray response) { List<Categories> newList = new ArrayList<>(); for (int i = 0; i < response.length(); i++) { try { Categories gradee = new Categories(); JSONObject json = response.getJSONObject(i); gradee.setImageUrl(json.getString(Config.TAG_G_IMAGE_URL)); gradee.setName(json.getString(Config.TAG_G_NAME)); newList.add(gradee); } catch (JSONException e) { e.printStackTrace(); } } // 计算新旧数据差异并更新列表 DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new CategoriesDiffCallback(listGrades, newList)); listGrades.clear(); listGrades.addAll(newList); diffResult.dispatchUpdatesTo(adapter); progressBar.setVisibility(View.GONE); }
这个方案的优势在于:
- 从根源避免重复,不需要额外的去重计算,大数据场景下性能远高于去重方案
- 所有数据操作都在UI线程完成,避免线程安全问题
- 可选的DiffUtil优化能进一步提升RecyclerView的更新效率
内容的提问来源于stack exchange,提问作者Dhruvbhati
相关产品推荐
相关产品推荐

