Я разрабатываю приложение для конкурса.Приложение подключено к базе данных реального времени Firebase, которая организована в несколько дочерних списков, каждый из которых имеет собственное строковое значение следующим образом:
category1:
child1: "string"
child2: "string"
category2:
child3: "string"
child4: "string"
(etc.)
Я пытаюсь получить имена этих категорий и добавить их ввыпадающий Spinner в одном из моих макетов.Однако когда я тестирую этот макет, происходит нечто особенное.Если я нажму на Spinner, чтобы открыть выпадающий список, он будет постоянно обновляться (я вижу, как он постоянно закрывается и снова открывается).Что еще более странно, так это то, что иногда он будет отображать только список из двух строк (которые я добавляю по умолчанию) и ни одно из названий категорий выше, но в других случаях он будет отображать их оба в списке.
Кажется, проблема обновления возникает независимо от того, пытаюсь ли я добавить дочерние строки из Firebase.Я могу сказать, что это происходит потому, что окно отладчика в Android Studio постоянно спамито
D/ViewRootImpl@a8fa8f6[PopupWindow:d00794f]: Relayout returned: old=[286,729][962,1113] new=[286,729][962,1113] result=0x1 surface={valid=true 531823960064} changed=false
, пока открыто раскрывающееся меню Spinner (в обоих случаях).Я попытался найти эту ошибку вверх (как в целом, так и по частям), но я не смог найти ничего полностью относящегося к тому, что я пытался выполнить.
Вот код, который добавляет список в Spinner (этот метод называетсякогда действие открыто):
public void onOpen() {
// This is not the complete method, but the relevant portion of it
final List<String> categories = new ArrayList<>();
categories.add(selectionEmpty);
categories.add(selectionCreateNew);
dbh.dbref.child("users").child("a_users_uid_goes_here").child("flashcards").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
categories.add(child.getKey());
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, categories);
setSelector.setAdapter(dataAdapter);
}
А вот OnItemSelectedListener, который я назначил Spinner:
AdapterView.OnItemSelectedListener selectSet = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) {
String selection = adapterView.getItemAtPosition(pos).toString();
if (selection.equals(selectionEmpty)) onOpen();
if (selection.equals(selectionCreateNew)) onCreateNewSet();
else onSelectSet(selection);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
};
onCreateNewSet()
и onSelectSet(String set)
в настоящее время являются двумя пустыми методами.Я не верю, что это должно иметь какое-либо влияние, но на всякий случай они ничего не делают в данный момент.onOpen()
приведен фрагмент кода выше.
Я впервые использую объекты Spinner, и я также новичок в Android Studio в целом (использую его 6 месяцев), поэтому я приношу свои извинения, если я 'м просто отсутствует очевидная строка кода.Подводя итог: оптимально, выпадающий список Spinner должен отображать две предустановленные строки и все имена категорий в базе данных и открываться только один раз.На самом деле происходит то, что он постоянно закрывается / открывается и показывает имена категорий из базы данных каждый раз, когда он открывается (однако предустановленные строки всегда есть).Я очень признателен за любую помощь!
Я могу в ближайшее время связать GIF с проблемой, с которой я сталкиваюсь, если кому-то понадобится.
ОБНОВЛЕНИЕ: Похоже, что это обновление происходит только тогда, когда у меня есть значение по умолчаниюзначение, выбранное в раскрывающемся списке, которое является одной из двух предустановленных строк.Если я выберу другой, то этот глюк не происходит.Все еще не уверен, почему это происходит.
ВТОРОЕ ОБНОВЛЕНИЕ: Я сам решил это, это была ошибка новичка, которую я смутился совершить.Проблема в том, что в методе onOpen()
я установил адаптер для Spinner, но затем в AdapterView.onItemSelectedListener
Spinner я снова вызываю onOpen()
, что привело к рекурсивному циклу, который нарушал все.Исправление состояло в том, чтобы создать дублирующий метод onOpen()
с именем onSelectNoSet()
, который делал то же самое, но НЕ устанавливал адаптер для счетчика, и чтобы слушатель вызывал этот метод вместо onOpen()
.
TL; DR рекурсия плохая