如何保证RecyclerView中Retrofit请求的onResponse回调顺序与请求顺序一致
RecyclerView请求响应顺序错位解决方案
- 按位置绑定响应,直接写入对应索引
不要按回调顺序往ArrayList追加数据,发起请求时先记录当前条目对应的adapterPosition,回调拿到结果后直接将数据写入ArrayList的对应索引位置,同时校验当前holder的位置是否和发起请求时的位置一致,避免holder复用导致的错误更新:
// onBindViewHolder 内逻辑 int currentPosition = holder.getAdapterPosition(); long currentItemId = dataList.get(currentPosition).getItemId(); // 取条目自身唯一ID // 优先读缓存 if (cacheMap.get(currentItemId) != null) { bindData(holder, cacheMap.get(currentItemId)); return; } Call<FotografiasGeoBean> call = restClient.getData(allNeededParams); call.enqueue(new Callback<FotografiasGeoBean>() { @Override public void onResponse(Call<FotografiasGeoBean> call, Response<FotografiasGeoBean> response) { if (!response.isSuccessful() || response.body() == null) return; // 校验位置有效性,排除holder复用导致的匹配错误 if (holder.getAdapterPosition() == currentPosition) { FotografiasGeoBean data = response.body(); // 直接写入对应索引位,不按回调顺序追加 dataList.set(currentPosition, data); notifyItemChanged(currentPosition); // 写入缓存 cacheMap.put(currentItemId, data); } } @Override public void onFailure(Call<FotografiasGeoBean> call, Throwable t) { // 异常处理逻辑 } }); // 将请求绑定到holder,方便后续回收时取消 holder.setCurrentCall(call);
用SparseArray做中间存储容器
如果需要批量归集请求结果,可使用SparseArray<FotografiasGeoBean>作为临时存储,key为条目位置/唯一ID,value为返回的响应数据,不管回调顺序如何,都会写入对应的key对应位置,所有请求完成后再统一转存到ArrayList即可。增加无效请求过滤机制
重写RecyclerView.Adapter的onViewRecycled方法,当条目被移出屏幕回收时,直接取消对应的未完成请求,避免无用回调返回后造成数据错乱,同时减少不必要的资源消耗:
@Override public void onViewRecycled(MyViewHolder holder) { super.onViewRecycled(holder); Call<?> currentCall = holder.getCurrentCall(); if (currentCall != null && !currentCall.isCanceled()) { currentCall.cancel(); } }
- 缓存key优先使用条目唯一ID
不要用position作为缓存key,列表下拉刷新、插入删除条目都会导致position变动,用条目自身的服务端唯一ID作为缓存key,能保证跳转回列表后缓存匹配的准确性,不会因为列表结构变动出现缓存错位。
内容的提问来源于stack exchange,提问作者user2638180
相关产品推荐
相关产品推荐

