【问题标题】:Make geoQuery.addGeoQueryEventListener() a blocking operation使 geoQuery.addGeoQueryEventListener() 成为阻塞操作
【发布时间】:2020-05-28 07:57:16
【问题描述】:

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

    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 之前退出。

【问题讨论】:

  • 你不能让你的firestore查询在回调中运行吗?不过,您可能必须返回一个异步类型,例如 CompletableFuture,但非阻塞 IO 通常是一件好事(除非您每个请求都有一个线程,那么这就不成问题了)。
  • 等等,query.get() 也在阻塞,不是吗?我不知道这个 API,但它看起来确实像一个阻塞操作。
  • 是的,query.get() 是一个阻塞操作,但它取决于非阻塞的 geoQuery.addGeoQueryEventListener() 的结果。 query.get() 不返回结果,因为它的前导没有及时获取数据。

标签: java google-cloud-firestore firebase-admin geofire geofirex


【解决方案1】:

请注意,我不知道您正在使用哪些 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 阻止。

旁注,请确保在您的情况下可以进行屏蔽。 应该没问题的一个例子是,当运行此代码的线程来自 HTTP 请求池(例如 Netty 的)时,因为这可能会产生争用并停止您的 Web 服务器处理新请求。

【讨论】:

  • 谢谢...这对我有用。我必须做的唯一改变是使我的 businessIds 对象不是最终的。我不明白原因。我想我需要了解更多关于 Completable future 和一般异步编程的知识。
  • @Gautamkapoor 嗯,这很奇怪,如果你最终确定了该字段,会有什么问题?
猜你喜欢
  • 1970-01-01
  • 2014-06-15
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-27
相关资源
最近更新 更多