为何onComplete方法执行完毕后numPoints变量未更新?
问题分析与解决方案
问题根源
Firebase Firestore的get()方法是异步非阻塞的:调用它后会立刻返回,不会等待网络请求完成就继续执行后续代码。
你的代码里,循环中每个get()的onComplete回调都是在后台线程执行的,而主线程会直接跳过这些异步操作,先执行最后的System.out.println("numPoints is " + numPoints);——这时候所有异步请求还没开始更新numPoints,所以打印的是初始值0。等后续异步请求陆续完成,才会在onComplete里累加并打印中间值,这就导致了输出顺序和预期不符。
解决方案
方案1:用CountDownLatch同步等待(注意:Android主线程慎用,会阻塞UI)
通过CountDownLatch计数,等待所有异步任务完成后再打印最终结果:
private void CalculateBatPoints(ArrayList<String> listBat) { numPoints = 0; CountDownLatch latch = new CountDownLatch(listBat.size()); for (int i = 0; i < listBat.size(); i++) { db.collection("players").document(listBat.get(i)).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { @Override public void onComplete(@NonNull Task<DocumentSnapshot> task) { try { if (task.isSuccessful()) { DocumentSnapshot ds = task.getResult(); String pointsStr = ds.getString("gwPoints"); if (pointsStr != null) { numPoints += Integer.parseInt(pointsStr); System.out.println(numPoints); } } } finally { // 每个任务完成后计数减1 latch.countDown(); } } }); } try { // 阻塞当前线程,直到所有任务完成 latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("numPoints is " + numPoints); }
方案2:用FirebaseTasks.whenAll异步等待(推荐Android环境使用)
利用Firebase提供的批量任务工具,异步等待所有请求完成后再处理结果,不会阻塞主线程:
private void CalculateBatPoints(ArrayList<String> listBat) { numPoints = 0; List<Task<DocumentSnapshot>> taskList = new ArrayList<>(); // 先收集所有异步查询任务 for (String playerId : listBat) { Task<DocumentSnapshot> queryTask = db.collection("players").document(playerId).get(); taskList.add(queryTask); } // 等待所有任务完成后统一处理 Tasks.whenAll(taskList).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> batchTask) { if (batchTask.isSuccessful()) { // 遍历所有任务结果累加分数 for (Task<DocumentSnapshot> singleTask : taskList) { DocumentSnapshot ds = singleTask.getResult(); String pointsStr = ds.getString("gwPoints"); if (pointsStr != null) { numPoints += Integer.parseInt(pointsStr); System.out.println(numPoints); } } System.out.println("numPoints is " + numPoints); } else { // 处理批量请求失败的情况 System.err.println("批量查询失败:" + batchTask.getException().getMessage()); } } }); }
内容的提问来源于stack exchange,提问作者coderMani
相关产品推荐
相关产品推荐

