使 geoQuery.addGeoQueryEventListener() 成为阻塞操作

Make geoQuery.addGeoQueryEventListener() a blocking operation

我为 Firestore 中的每个文档保存了一个包含一些虚拟数据的商店列表和 latitude/longitudes。我想在 poi 附近获取文件。为此,我使用了 GeoFire 库。 现在,我可以从 geoQuery.addGeoQueryEventListener() 方法中对数据进行排序,但此方法不是阻塞操作,因此我的代码在 geoQuery.addGeoQueryEventListener() 可以 return 排序列表之前退出。下面是代码片段:

    List<QueryDocumentSnapshot> doc = new ArrayList<>();
    List<String> businessIds = new ArrayList<>();
    Set<Business> businessSet = new HashSet<>();

    GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(latitude, longitude), 2000);
    geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {

        @Override
        public void onKeyEntered(String key, GeoLocation location) {
            // TODO Auto-generated method stub
            businessIds.add(key);
        }

        @Override
        public void onKeyExited(String key) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onKeyMoved(String key, GeoLocation location) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onGeoQueryReady() {
            // TODO Auto-generated method stub
            System.out.println("All initial data has been loaded and events have been fired!");
        }

        @Override
        public void onGeoQueryError(DatabaseError error) {
            // TODO Auto-generated method stub
            System.err.println("There was an error with this query: " + error);
        }

    });
    geoQuery.removeAllListeners();

    ApiFuture<QuerySnapshot> query = firestore.collection("business").whereIn("businessId", businessIds).get();
    businessSet = query.get().getDocuments().stream()
            .map(b -> b.toObject(Business.class)).collect(Collectors.toSet());
    return businessSet;

在上面的代码中,我的程序在 onKeyEntered() 中将键添加到 businessIds 之前退出。

请注意,我不知道您正在使用的那些 API,但理论上,您应该能够使用 CompletableFuture,例如像这样的东西(未测试):

private CompletableFuture<List<String>> runGeoQuery(double latitude, double longitude) {
  CompletableFuture<List<String>> future = new CompletableFuture<>();
  GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(latitude, longitude), 2000);
  geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {

    private final List<String> businessIds = new ArrayList<>();

    @Override
    public void onKeyEntered(String key, GeoLocation location) {
      businessIds.add(key);
    }

    @Override
    public void onKeyExited(String key) {
    }

    @Override
    public void onKeyMoved(String key, GeoLocation location) {
    }

    @Override
    public void onGeoQueryReady() {
      future.complete(businessIds);
    }

    @Override
    public void onGeoQueryError(DatabaseError error) {
      future.completeExceptionally(error);
    }

  });
  return future;
}

然后,您可以使用#thenApply 或#thenCompose 对结果进行组合,或者您可以简单地使用#get 进行阻塞。

旁注,只要确保阻止适合您的情况即可。一个应该 not 没问题的例子是当线程 运行 此代码来自 HTTP 请求池(例如 Netty 的)时,因为这可能会引起争用并停止您的网络服务器处理新请求。