Android ListView执行多次clear操作仍存在重复项如何解决?
问题原因及修复方案
核心问题原因
- 重复注册Firebase
ChildEventListener:onCreate方法末尾已经调用了一次getData(),首次启动时onCreate执行完后立刻会执行onResume,onResume里又调用了一次getData(),每次调用getData()都会给数据库节点添加一个新的监听器。同一个节点存在多个监听器的情况下,每一条数据会触发多次onChildAdded回调,导致同一条数据被多次添加到列表中,出现重复项。 - 监听器没有移除逻辑:每次页面切走再切回,都会新增一个监听器,重复问题会越来越严重。
- 多余的适配器重建逻辑:
onResume里清空适配器再重建是完全多余的操作,反而会增加不必要的性能消耗。
修复方案
第一步:新增全局监听器变量,避免重复注册
在Activity的成员变量区域新增以下代码:
// 持有ChildEventListener实例,方便后续移除 private ChildEventListener guestListChildListener;
第二步:改造getData方法,增加监听器去重和数据去重逻辑
public void getData() { // 先移除之前注册的监听器,避免重复监听 if (guestListChildListener != null) { dbReferenceEvent.child(eventId).child("guestList").removeEventListener(guestListChildListener); } guestsArrayList.clear(); guestListAdapter.notifyDataSetChanged(); guestListChildListener = new ChildEventListener() { @Override public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) { Guest guest = snapshot.getValue(Guest.class); guest.guestKey = snapshot.getKey(); // 增加本地去重判断,避免极端情况重复添加 boolean isExist = false; for (Guest g : guestsArrayList) { if (g.guestKey.equals(guest.guestKey)) { isExist = true; break; } } if (!isExist) { guestsArrayList.add(guest); guestListAdapter.notifyDataSetChanged(); } } @Override public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) { // 实现数据更新逻辑,同步修改列表中对应的数据 String updateKey = snapshot.getKey(); Guest updateGuest = snapshot.getValue(Guest.class); updateGuest.guestKey = updateKey; for (int i = 0; i < guestsArrayList.size(); i++) { if (guestsArrayList.get(i).guestKey.equals(updateKey)) { guestsArrayList.set(i, updateGuest); guestListAdapter.notifyDataSetChanged(); break; } } } @Override public void onChildRemoved(@NonNull DataSnapshot snapshot) { // 实现数据删除逻辑,同步移除列表中对应的数据 String removeKey = snapshot.getKey(); for (int i = 0; i < guestsArrayList.size(); i++) { if (guestsArrayList.get(i).guestKey.equals(removeKey)) { guestsArrayList.remove(i); guestListAdapter.notifyDataSetChanged(); break; } } } @Override public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) { } @Override public void onCancelled(@NonNull DatabaseError error) { } }; dbReferenceEvent.child(eventId).child("guestList").addChildEventListener(guestListChildListener); }
第三步:简化onResume逻辑,删除多余操作
@Override public void onResume() { super.onResume(); // 只需要调用getData即可,不需要重建适配器 getData(); }
第四步:删除onCreate末尾多余的调用
将onCreate方法末尾的以下代码删除:
guestsArrayList.clear(); guestListAdapter.clear(); guestListAdapter.notifyDataSetChanged(); getData();
第五步:添加页面销毁时的监听器移除逻辑,避免内存泄漏
@Override protected void onDestroy() { super.onDestroy(); if (guestListChildListener != null) { dbReferenceEvent.child(eventId).child("guestList").removeEventListener(guestListChildListener); } }
内容的提问来源于stack exchange,提问作者Ludwig
相关产品推荐
相关产品推荐

