Данные, полученные из FirebaseDatabase, отображаются в трех отдельных AlertDialogs вместо одного
Я извлекаю некоторые данные из FirebaseDatabase
, а затем помещаю их в array
, а затем пытаюсь показать их в List
, который находится в пользовательском AlertDialog
.
Здесь код:
query = mDatabase.child("child").child(anotherChild).child("yetAnotherChild");
uProfile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
query.orderByChild("someChild").addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
Map<String, String> newD = (Map<String, String>) dataSnapshot.getValue();
ArrayList<String> l = new ArrayList<String>();
l.add(newD.get("lol").substring(30));
String names[] = l.toArray(new String[0]);
AlertDialog.Builder alertDialog = new AlertDialog.Builder(Activity.this);
LayoutInflater inflater = getLayoutInflater();
View convertView = inflater.inflate(R.layout.dialog_list, null);
alertDialog.setView(convertView);
alertDialog.setTitle("title");
ListView lv = (ListView) convertView.findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_list_item_1, names);
lv.setAdapter(adapter);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
alertDialog.show();
} else {
Toast.makeText(getBaseContext(), "NULLLLL", Toast.LENGTH_SHORT).show();
}
}
...
...
});
}
});
Здесь структура базы данных:
app
-child
-anotherChild
-yetAnotherChild
-inaccessibleChild
-someChild: "value"
-lol: "value"
Я не могу использовать valueEventListener()
здесь, так как у меня нет доступа к inaccessibleChild
. inaccessibleChild
здесь uid
других пользователей, которые следовали за определенным пользователем. Как я могу получить доступ там uid
?
Проблема заключается в том, что данные извлекаются, но вместо того, чтобы отображаться в списке в одном AlertDialog
, он отображается один за другим в 3 отдельный AlertDialog
.
Что здесь происходит?
Пожалуйста, дайте мне знать.
Ответы
Ответ 1
Ну, ни один из вышеперечисленных ответов не помог, хотя ответ Linxy правильный, я видел его после решения проблемы.
Перемещение всего кода и запись этой строки: alertDialog.show();
внутри setOnClickListener()
улучшает мой код:
query = mDatabase.child("child").child(anotherChild).child("yetAnotherChild");
query.orderByChild("someChild").addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
Map<String, String> newD = (Map<String, String>) dataSnapshot.getValue();
ArrayList<String> l = new ArrayList<String>();
l.add(newD.get("lol").substring(30));
String names[] = l.toArray(new String[0]);
AlertDialog.Builder alertDialog = new AlertDialog.Builder(Activity.this);
LayoutInflater inflater = getLayoutInflater();
View convertView = inflater.inflate(R.layout.dialog_list, null);
alertDialog.setView(convertView);
alertDialog.setTitle("title");
ListView lv = (ListView) convertView.findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_list_item_1, names);
lv.setAdapter(adapter);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
} else {
Toast.makeText(getBaseContext(), "NULLLLL", Toast.LENGTH_SHORT).show();
}
}
...
...
});
uProfile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
alert11.show();
}
});
В любом случае, я хотел бы поблагодарить всех, кто ответил на этот вопрос.
Мир.
Ответ 2
транзакции Firebase являются асинхронными, поэтому ваша начальная строка для добавления 3-х детей происходит после того, как вы установите слушателя, поэтому ваш обратный вызов вызывается 3 раза. (создание 3 диалоговых окон).
Переместите эту строку за пределы щелчка:
query = mDatabase.child("child").child(anotherChild).child("yetAnotherChild");
Затем, когда вы добавляете ниже прослушивателя (внутри клика), он должен быть ОК
query.orderByChild("someChild").addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Ответ 3
Положите ограничение при использовании valueEventListener
или addChildEventListener
. например,
int limit = 100;
databaseRef.child("chats").limitToLast(limit).addValueEventListener(listener);
И всегда удаляйте прослушиватель, когда вы делали свою работу, связанную с firebase. например,
databaseRef.child("chats").limitToLast(limit).removeEventListener(listener);
Спасибо.
Ответ 4
Создайте и покажите AlertDialog перед вызовом .addChildEventListener()
Затем используйте внутри addChildEventListener вызов notifyDatasetChanged() после того, как вы скачали соответствующие данные. Не создавайте AlertDialog внутри addChildEventListener
Ответ 5
Вы можете использовать запросы Firebase для ограничения данных, загружаемых слушателем.
query.orderByChild("someChild").limitToLast(1).addChildEventListener(...
Ответ 6
@Blundell имеет представление о решении вашей проблемы. Я просто хочу предложить вам аналогичный подход с addValueEventListener
.
Слушатель события значения запускает один раз для начального состояния данных, а затем снова каждый раз, когда изменяется значение этих данных.
Вам нужно вытащить запрос firebase из функции onClick
. Таким образом, ваш запрос может выглядеть так.
// Declare the variable names as public
private String names[];
private void addFirebaseListener() {
ref = mDatabase.child("child").child(anotherChild).child("yetAnotherChild");
ref. userRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
Map<String, String> newD = (Map<String, String>) dataSnapshot.getValue();
ArrayList<String> l = new ArrayList<String>();
l.add(newD.get("lol").substring(30));
names[] = l.toArray(new String[0]);
// Call notifyDataSetChanged each time your array gets updated
adapter.notifyDataSetChanged();
}
@Override public void onCancelled(FirebaseError error) { }
});
}
Теперь напишите функцию, чтобы показать ListView
в AlertDialog
// Declare the adapter as public and initialize it with null
private ArrayAdapter<String> adapter = null;
private void showListInDialog() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(Activity.this);
LayoutInflater inflater = getLayoutInflater();
View convertView = inflater.inflate(R.layout.dialog_list, null);
alertDialog.setView(convertView);
alertDialog.setTitle("title");
ListView lv = (ListView) convertView.findViewById(R.id.lv);
if(adapter == null)
adapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_list_item_1, names);
// Now set the adapter
lv.setAdapter(adapter);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
alertDialog.dismiss();
}
});
alertDialog.show();
}
Теперь в вашей функции onCreate
вам нужно сначала установить прослушиватель Firebase, а затем установить функцию onClick
следующим образом.
uProfile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showListInDialog();
}
});
Ответ 7
@Hammad Попробуйте этот модифицированный код, основываясь на ваших требованиях.
query = mDatabase.child("child").child(anotherChild).child("yetAnotherChild");
AlertDialog alertDialog;
ArrayList<String> l;
uProfile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
query.orderByChild("someChild").addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
Map<String, String> newD = (Map<String, String>) dataSnapshot.getValue();
if(l == null) {
l = new ArrayList<String>();
}
l.add(newD.get("lol").substring(30));
String names[] = new String[l.size()];
for(int length=0; length < l.size(); l++) {
names[length] = l.get(length);
}
if(alertDialog == null) {
alertDialog = new AlertDialog.Builder(Activity.this).create();
LayoutInflater inflater = getLayoutInflater();
View convertView = inflater.inflate(R.layout.dialog_list, null);
alertDialog.setView(convertView);
alertDialog.setTitle("title");
ListView lv = (ListView) convertView.findViewById(R.id.lv);
} ArrayAdapter<String> adapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_list_item_1, names);
lv.setAdapter(adapter);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
if(!alertDialog.isShowing()) {
alertDialog.show();
}
} else {
Toast.makeText(getBaseContext(), "NULLLLL", Toast.LENGTH_SHORT).show();
}
}
...
...
});
}
});
Ответ 8
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
/**
Получить списки элементов или прослушать добавления в список элементов. Этот обратный вызов запускается один раз для каждого существующего дочернего элемента, а затем снова каждый раз, когда новый ребенок добавляется к указанному пути. DataSnapshot, переданный слушателю, содержит новые дочерние данные.
**/
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
ref.addChildEventListener(childEventListener);
Использование ChildEventListener onChildAdded - это вызов на каждого ребенка, который у вас есть в этом node. Означает, что ваш код запускается 3 раза, поэтому диалоговое окно 3 раза.
Это проблема
Таким образом, решение:
При использовании ChildEventListener рекомендуется прочитать списки данных, есть ситуации, при которых полезно использовать ValueEventListener для ссылки на список.
Прикрепление ValueEventListener к списку данных вернет весь список данных как один DataSnapshot, который вы затем можете перебрать для доступа к отдельным детям.
Даже если для запроса имеется только одно совпадение, моментальный снимок по-прежнему является списком; он просто содержит один элемент. Чтобы получить доступ к элементу, вам необходимо выполнить цикл:
inaccessibleChild.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
//here you can access the each child of that node.
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});