Сделайте geoQuery.addGeoQueryEventListener () блокирующей операцией - PullRequest
0 голосов
/ 28 мая 2020

Я сохранил список магазинов с некоторыми фиктивными данными и широтой / долготой для каждого документа в Firestore. Я хочу получить документы рядом с пои. Для этого я использовал библиотеку GeoFire. Теперь я могу сортировать данные внутри метода geoQuery.addGeoQueryEventListener (), но этот метод не является блокирующей операцией, поэтому мой код завершается до того, как geoQuery.addGeoQueryEventListener () сможет вернуть отсортированный список. Ниже приведен фрагмент кода:

    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;

В приведенном выше коде Моя программа завершается до того, как ключ может быть добавлен к businessIds в onKeyEntered ().

1 Ответ

1 голос
/ 28 мая 2020

Обратите внимание, что я не знаю тех 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), так как это может создать конкуренцию и остановить ваш веб-сервер, обрабатывающий новые запросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...