Доступ к данным внутри внутренней функции в Java с FireBase / FireStore - PullRequest
0 голосов
/ 30 октября 2018

Я пишу приложение для Android, используя бэкэнд Google FireStore. Код для сбора всех документов в коллекции пожарного депо следующий из официальной документации:

db.collection("cities")
    .get()
    .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                    Log.d(TAG, document.getId() + " => " + document.getData());
                }
            } else {
                Log.d(TAG, "Error getting documents: ", task.getException());
            }
        }
    });

Если вышеприведенный код выводит в Log.d(...), я бы хотел, чтобы моя программа добавила результаты вызова document.getData() в ArrayList, доступный вне внутреннего класса / метода. Я не уверен, что это лучший способ сделать это. Попытка изменить возвращаемый тип возврата метода onComplete приводит к ошибкам. Существует ли стандартный способ доступа к элементам в таких методах?

Объявление переменной и попытка ее изменения в классе также невозможны, если только переменная не является окончательной, что побеждает точку.

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Это асинхронный вызов (он запускает фоновый процесс для выполнения запроса Firebase, и как только он выполняется, он выполняет ваш onComplete слушатель), поэтому вы не можете ожидать, что данные будут под рукой сразу после выполнения вызов базы данных. Например, если ваша функция выглядит как

void getData() {
    final List<MyData> list = new ArrayList<>();

    db.collection("cities")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        Log.d(TAG, document.getId() + " => " + document.getData());
                        list.add(new MyData(document.getData()));
                    }
                } else {
                    Log.d(TAG, "Error getting documents: ", task.getException());
                }
            }
        });

    Log.d(TAG, "List size = " + list.size()); // will print 0
    // list will be empty here, the firebase call will take hundreds 
    // to thousands of milliseconds to complete
}

Вам необходимо структурировать свою программу так, чтобы она могла ожидать поступления данных. Есть несколько способов сделать это. Можно было бы иметь list членом класса, который заполняется слушателем onComplete (тогда вы должны структурировать программу для обработки данных, поступающих в случайные моменты времени).

Другим способом было бы иметь процедуру обработки данных, которая принимает ArrayList и что-то с ним делает. Этот метод может быть вызван из прослушивателя onComplete, как только вы получите все данные. Например:

void getData() {
    db.collection("cities")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    List<MyData> list = new ArrayList<>();
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        Log.d(TAG, document.getId() + " => " + document.getData());
                        list.add(new MyData(document.getData()));
                    }
                    processData(list);
                } else {
                    Log.d(TAG, "Error getting documents: ", task.getException());
                }
            }
        });
}

void processData(List<MyData> data) {
    // do stuff with the data, or make a copy, or otherwise share it
    // with the rest of your program
}
0 голосов
/ 30 октября 2018

Я бы хотел, чтобы моя программа добавила результаты вызова document.getData () в ArrayList, доступный за пределами внутреннего класса / метода.

В этом случае, если вы используете класс модели, вы должны использовать метод toObject() и добавить объекты типа YourModelClass в ArrayList, например:

if (task.isSuccessful()) {
    List<YourModelClass> list = new ArrayList<>();
    for (QueryDocumentSnapshot document : task.getResult()) {
        YourModelClass yourModelClass = document.toObject(YourModelClass.class);
        list.add(yourModelClass);

        //Do what you need to do with your list
    }
}

Как видите, я посоветовал вам использовать список YourModelClass объектов внутри обратного вызова. Это связано с тем, что метод onComplete() имеет асинхронное поведение, и вы не можете просто использовать этот список вне обратного вызова, потому что он всегда будет пустым.

Попытка изменить тип возвращаемого значения метода onComplete приводит к ошибкам.

Изменение типа возвращаемого значения метода не приведет к ошибкам, но результатом всегда будет пустой список. Вы не можете вернуть то, что еще не загружено. Быстрое решение этой проблемы - использовать этот список объектов только внутри метода onComplete(), как я уже писал выше, или, если вы хотите использовать его снаружи, я рекомендую вам посмотреть последнюю часть моего ответа из этого post , в котором я объяснил, как это можно сделать с помощью пользовательского обратного вызова. Вы также можете взглянуть на это видео для лучшего понимания.

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