如何等待所有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()); } });
关键注意事项:
- 替换
addValueEventListener为addListenerForSingleValueEvent或get():你只需要读取一次数据做对比,不需要实时监听数据变化,减少资源消耗。 - 使用
AtomicInteger计数:异步回调在不同线程执行,普通int会有线程安全问题,AtomicInteger可以保证计数准确。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

