Запрос данных из firebase

Я пытаюсь получить список элементов из моей базы данных Firebase... но у меня проблема с получением их. Мой код выглядит примерно так:

List<Items> itemsList;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_work_items_report);

    itemsList = GetItems();
}

и метод, который должен вернуть мои элементы, выглядит так:

private ArrayList<Items> GetItems(){
    DatabaseReference database = FirebaseDatabase.getInstance().getReference();
    DatabaseReference ref = database.child("items");
    final ArrayList<Items> itemsRez = new ArrayList<Items>();
    Query itemsQuery = ref.orderByChild("type");

    itemsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
                    Items item = singleSnapshot.getValue(Items.class);
                    itemsRez.add(item);
                }
            }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    return itemsRez;
}

GetItems() всегда возвращает мне нулевой список, что имеет смысл, так как нет ничего, что могло бы вызвать событие onDataChange, прежде чем я возвращал этот список, поэтому мой вопрос... как я могу сделать этот метод, чтобы вернуть список элементов из БД?

1 ответ

Решение

Когда вы звоните addListenerForSingleValueEvent() клиент Firebase начинает загрузку данных с сервера, что может занять некоторое время. Чтобы предотвратить блокирование вашего приложения (что может привести к появлению диалогового окна "Приложение не отвечает"), оно загружает данные в отдельный поток. Таким образом, пока данные загружаются, ваш основной поток продолжается и возвращает текущее состояние itemsRez, который является пустым списком.

Проще всего это увидеть, если вы добавите несколько операторов регистрации в ваш код:

private ArrayList<Items> GetItems(){
    DatabaseReference database = FirebaseDatabase.getInstance().getReference();
    DatabaseReference ref = database.child("items");
    final ArrayList<Items> itemsRez = new ArrayList<Items>();
    Query itemsQuery = ref.orderByChild("type");

    System.out.println("Attaching listener");
    itemsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
                    Items item = singleSnapshot.getValue(Items.class);
                    itemsRez.add(item);
                }
            }
            System.out.println("Received "+itemsRez.size()+" items");
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    System.out.println("Returning "+itemsRez.size()+" items");
    return itemsRez;
}

Вопреки тому, что вы, вероятно, ожидаете, это напечатает регистрацию в следующем порядке:

Прикрепление слушателя

Возврат 0 товаров

Полученные предметы

Одним из распространенных решений вашей проблемы является переосмысление цели вашего кода. Вместо того, чтобы писать "сначала возьмите предметы, затем сделайте с ними abc", напишите код как "начните получать предметы. Затем, когда они придут, сделайте с ними abc". В коде это означает, что вы перемещаете код, который нужен itemsRec в onDataChange метод, где он будет вызван в нужный момент: когда элементы загружены.

Также см:

Другие вопросы по тегам