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

Android:Firebase双应用下Admin端实时获取pelanggaran数据异常

实现管理员端实时获取Pelanggaran数据的方案

咱们先拆解下你现有代码的核心问题,再一步步修改实现实时更新:

现有代码的问题

  1. 用户列表无法实时更新:你用了addListenerForSingleValueEvent监听User节点,这只会一次性拉取当前用户数据,后续新增/删除用户不会触发更新。
  2. 重复监听与内存泄漏风险:每次调用refreshList()都会为每个用户添加新的addValueEventListener,旧的监听没有被移除,会导致重复接收数据和内存泄漏。
  3. 适配器更新时机错误:你在User节点的onDataChange末尾直接创建并设置适配器,但嵌套的Pelanggaran节点监听是异步执行的,这时候pelanggaranList可能还没填充数据,导致列表不显示内容。

修改后的完整代码

下面是修正后的代码,我会在关键部分加注释说明:

// 全局变量:保存每个用户的Pelanggaran监听,用于后续移除避免内存泄漏
private Map<String, ValueEventListener> pelanggaranListeners = new HashMap<>();
private PelanggaranAdapter pelanggaranAdapter;
private ArrayList<Pelanggaran> pelanggaranList;
private ValueEventListener userValueEventListener; // 保存用户列表监听,用于销毁时移除

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 初始化列表和适配器,只需要一次
    pelanggaranList = new ArrayList<>();
    pelanggaranAdapter = new PelanggaranAdapter(MainActivity.this, pelanggaranList);
    recyclerView.setAdapter(pelanggaranAdapter);
    
    // 启动实时监听
    startRealTimeListeners();
}

private void startRealTimeListeners() {
    DatabaseReference databaseUser = FirebaseDatabase.getInstance().getReference("User");
    
    // 用addValueEventListener替代SingleValueEvent,实时监听用户列表变化
    userValueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // 1. 先清空旧数据和旧监听
            pelanggaranList.clear();
            removeAllPelanggaranListeners();
            
            // 2. 遍历所有用户,为每个用户的Pelanggaran添加实时监听
            for (DataSnapshot dsUser : dataSnapshot.getChildren()) {
                User user = dsUser.getValue(User.class);
                if (user == null) continue; // 避免空指针
                final String userId = user.getUserId();
                
                DatabaseReference pelanggaranRef = FirebaseDatabase.getInstance().getReference("Pelanggaran").child(userId);
                ValueEventListener pelanggaranListener = new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot1) {
                        // 先移除该用户的旧数据,避免重复添加
                        Iterator<Pelanggaran> iterator = pelanggaranList.iterator();
                        while (iterator.hasNext()) {
                            Pelanggaran p = iterator.next();
                            if (p.getUserId().equals(userId)) { // 假设Pelanggaran类有getUserId方法
                                iterator.remove();
                            }
                        }
                        
                        // 添加该用户的最新Pelanggaran数据
                        for (DataSnapshot dsPelanggaran : dataSnapshot1.getChildren()) {
                            Pelanggaran pelanggaran = dsPelanggaran.getValue(Pelanggaran.class);
                            if (pelanggaran != null) {
                                pelanggaran.setUserId(userId); // 确保每个Pelanggaran关联正确的用户ID
                                pelanggaranList.add(pelanggaran);
                            }
                        }
                        
                        // 通知适配器数据更新
                        pelanggaranAdapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        Log.e("PelanggaranListen", "用户" + userId + "的违规数据监听失败", databaseError.toException());
                    }
                };
                
                // 保存监听,后续用于移除
                pelanggaranListeners.put(userId, pelanggaranListener);
                pelanggaranRef.addValueEventListener(pelanggaranListener);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.e("UserListen", "用户列表监听失败", databaseError.toException());
        }
    };
    
    databaseUser.addValueEventListener(userValueEventListener);
}

// 移除所有Pelanggaran节点的监听,避免内存泄漏
private void removeAllPelanggaranListeners() {
    for (Map.Entry<String, ValueEventListener> entry : pelanggaranListeners.entrySet()) {
        DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Pelanggaran").child(entry.getKey());
        ref.removeEventListener(entry.getValue());
    }
    pelanggaranListeners.clear();
}

// 在Activity销毁时移除所有监听,彻底避免内存泄漏
@Override
protected void onDestroy() {
    super.onDestroy();
    removeAllPelanggaranListeners();
    if (userValueEventListener != null) {
        FirebaseDatabase.getInstance().getReference("User").removeEventListener(userValueEventListener);
    }
}

关键修改说明

  • 全局适配器初始化:只在onCreate里初始化一次适配器,后续只更新数据并通知适配器,避免重复创建。
  • 实时监听用户列表:用addValueEventListener监听User节点,用户新增/删除时都会触发onDataChange。
  • 管理Pelanggaran监听:用HashMap保存每个用户的监听,在用户列表变化时先移除旧监听,再添加新的,避免重复监听。
  • 数据去重与更新:每次获取某个用户的Pelanggaran数据时,先移除该用户的旧数据,再添加新数据,避免列表重复。
  • 内存泄漏防护:在onDestroy里移除所有监听,确保Activity销毁时没有残留的Firebase监听。

额外建议

如果你的业务允许,也可以考虑优化Firebase数据结构,比如在根节点下新增一个AllPelanggaran节点,每次用户端新增Pelanggaran时,同时写入Pelanggaran/{userId}和AllPelanggaran,这样管理员端只需要监听AllPelanggaran一个节点,就能实时获取所有数据,不需要遍历所有用户,性能会更好。

内容的提问来源于stack exchange,提问作者Ivana Natalia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:31:20