Запрос данных из 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
метод, где он будет вызван в нужный момент: когда элементы загружены.
Также см: