java - 等待 Firebase 异步回调在循环内完成
问题描述
我正在尝试获取一堆分散在我的 Firebase 实时数据库中不同路径的数据。我运行了 n 次 for 循环,并且在每次迭代中,数据库的路径都是根据某些逻辑确定的。
然后我创建一个 Firebase 查询(将每次迭代中每个路径的 firebase 子响应限制为 1)并附加一个 addListenerForSingleValueEvent 到它。在 onDataChange 内部,我使用在 for 循环中声明为 final 的变量(索引)将接收到的数据元素附加到固定大小的列表 (X) 中。这样,索引变量跟踪对数据库的所有 n 调用,就好像它们并行运行一样,我可以将此列表 X 映射到其他几个列表。到目前为止,一切都很好。
现在,一旦这些 n 个异步回调完成返回它们的响应,我想调用一个自定义接口回调来将此数据发送到程序的某个部分。
但显然,for 循环不会等待这 n 个网络操作结束,并且我的 List X 在我尝试调用我的自定义回调接口的实例中保持为空。
在 n 个数据库调用完成其工作后,如何调用我的自定义接口回调?
代码是这样的:
.
.
.
for (int i = 0; i < n; i++) {
final int index = i;
.
.
.
//Y and X = some variable that changes every loop
//countryCode = some variable that changes every loop
Query query = mReference.child(Y + "/" + countryCode + "/" + X).limitToFirst(1);
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
for (DataSnapshot D : snapshot.getChildren()) {
<DataType> n = D.getValue(DataType.class);
keys.add(D.getKey());
X.set(index, n);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
} //end of for loop
//Control reaches here before callbacks are over
//Want to call custom callback here once all data is received
解决方案
实现您想要的一种方法是使用Future。您可以等到所有响应都返回,方法是将它们包装在一个大的CompletableFuture<Boolean>
. 在您上面写的内容之上的一个粗略示例:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
...
private CompletableFuture<Boolean> queryDatabaseAsync() {
CompletableFuture<Boolean> future = new CompletableFuture<>();
// if at least one fails then flag will switch
AtomicBoolean isSuccess = new AtomicBoolean(true);
AtomicInteger stack = new AtomicInteger(n);
for (int i = 0; i < n; i++) {
final int index = i;
Query query = ...;
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
...
// finish if last
if (stack.decrementAndGet() < 1) {
future.complete(isSuccess.get());
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
...
isSuccess.set(false);
// finish if last
if (stack.decrementAndGet() < 1) {
future.complete(isSuccess.get());
}
}
});
}
return future;
}
private void hitDatabase() {
if (myFuture != null) {
myFuture.cancel(true);
myFuture = null;
}
myFuture = queryDatabaseAsync();
myFuture.thenAccept(isSuccess -> {
// yay!
});
}
推荐阅读
- java - KeycloakWebSecurityConfigurerAdapter 和 JBoss stadalon.xml
- vue.js - 修复第一列时vue可拖动问题我无法移动列
- javascript - 浏览器中的文本区域列大小不一致
- php - laravel 文件上传 - “”文件不存在或不可读
- python - 如何从另一个屏幕类调用 Python 中的函数?
- excel - excel公式 - 查找和替换字符串的其余部分
- html - (Swift) 为什么 webView 从不显示我的本地图像?
- selenium - Android 模拟器在测试运行期间崩溃
- cmake - boost bjam 作为 cmake 外部项目失败
- node.js - 如何用 node js express 响应 xml?