Данные, полученные из 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());
    // ...
}

});