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

如何等待所有Firebase异步操作完成后统计修改次数?

解决Firebase异步操作完成后统计修改总数的问题

问题核心在于Firebase的数据库读取、写入操作都是异步执行的,而你的循环是同步执行的——循环跑完时,大部分甚至全部Firebase的检查和修改操作还没完成,所以modifications无法统计到正确数值。

下面给出两种可行的解决方法:

方案一:用CountDownLatch等待所有任务完成

CountDownLatch可以让主线程阻塞,直到所有异步任务执行完毕再继续。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

// 用AtomicInteger保证多线程下计数安全
AtomicInteger modifications = new AtomicInteger(0);
// 初始化计数器,后续动态更新任务数
CountDownLatch latch = new CountDownLatch(0);

for (int i = 0; i < dataInfo.size(); i++) {
    int finalI = i;
    // 改用addListenerForSingleValueEvent,只读取一次数据(无需持续监听)
    MESSAGE_REFERENCE.child("MyTable_" + myIndex).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            if(dataSnapshot.exists()){
                // 收集当前数据项的所有修改任务
                List<Task<Void>> currentTasks = new ArrayList<>();

                // 检查并添加_user_id修改任务
                if (!Objects.equals(dataSnapshot.child("_user_id").getValue(), dataInfo.get(finalI).get(1).toString())){
                    Task<Void> updateTask = dataSnapshot.child("_user_id").getRef().setValue(dataInfo.get(finalI).get(1).toString());
                    currentTasks.add(updateTask);
                }

                // 检查并添加_location修改任务
                if (!Objects.equals(dataSnapshot.child("_location").getValue(), dataInfo.get(finalI).get(2).toString())) {
                    Task<Void> updateTask = dataSnapshot.child("_location").getRef().setValue(dataInfo.get(finalI).get(2).toString());
                    currentTasks.add(updateTask);
                }

                // 更新计数器并绑定任务完成回调
                if (!currentTasks.isEmpty()) {
                    // 动态增加需要等待的任务数
                    latch = new CountDownLatch(latch.getCount() + currentTasks.size());
                    for (Task<Void> task : currentTasks) {
                        task.addOnCompleteListener(t -> {
                            if (t.isSuccessful()) {
                                modifications.incrementAndGet();
                            }
                            // 任务完成,计数器减1
                            latch.countDown();
                        });
                    }
                }
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            // 读取失败时也要减少计数器,避免主线程一直阻塞
            latch.countDown();
        }
    });
}

// 等待所有任务完成后输出结果
try {
    latch.await();
    System.out.println("完成的修改总数:" + modifications.get());
} catch (InterruptedException e) {
    e.printStackTrace();
}

方案二:用Firebase Tasks.whenAll()批量管理任务

利用Firebase原生的Task API,批量收集所有修改任务,等待全部完成后统计结果:

import com.google.android.gms.tasks.Tasks;
import java.util.concurrent.atomic.AtomicInteger;

List<Task<Void>> allUpdateTasks = new ArrayList<>();
AtomicInteger modifications = new AtomicInteger(0);

for (int i = 0; i < dataInfo.size(); i++) {
    int finalI = i;
    // 用get()方法包装读取操作,返回Task<DataSnapshot>
    MESSAGE_REFERENCE.child("MyTable_" + myIndex).get().addOnSuccessListener(dataSnapshot -> {
        if(dataSnapshot.exists()){
            // 处理_user_id修改
            if (!Objects.equals(dataSnapshot.child("_user_id").getValue(), dataInfo.get(finalI).get(1).toString())){
                Task<Void> updateTask = dataSnapshot.child("_user_id").getRef().setValue(dataInfo.get(finalI).get(1).toString());
                updateTask.addOnSuccessListener(v -> modifications.incrementAndGet());
                allUpdateTasks.add(updateTask);
            }

            // 处理_location修改
            if (!Objects.equals(dataSnapshot.child("_location").getValue(), dataInfo.get(finalI).get(2).toString())) {
                Task<Void> updateTask = dataSnapshot.child("_location").getRef().setValue(dataInfo.get(finalI).get(2).toString());
                updateTask.addOnSuccessListener(v -> modifications.incrementAndGet());
                allUpdateTasks.add(updateTask);
            }
        }
    }).addOnFailureListener(e -> {
        // 处理数据读取失败的情况
        Log.e("Firebase", "读取数据失败", e);
    });
}

// 等待所有修改任务完成
Tasks.whenAll(allUpdateTasks).addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
        System.out.println("完成的修改总数:" + modifications.get());
    } else {
        Log.e("Firebase", "部分修改任务执行失败", task.getException());
    }
});

关键注意事项:

  1. 替换addValueEventListener为addListenerForSingleValueEvent或get():你只需要读取一次数据做对比,不需要实时监听数据变化,减少资源消耗。
  2. 使用AtomicInteger计数:异步回调在不同线程执行,普通int会有线程安全问题,AtomicInteger可以保证计数准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:55:19