You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 17:54:03