从 FirebaseDatabase 获取的数据显示在 3 个单独的 AlertDialogs 而不是一个
Data fetched from FirebaseDatabase is getting shown in 3 separate AlertDialogs instead of one
我正在从 FirebaseDatabase
中获取一些数据,然后将它们放入 array
中,然后尝试在自定义 [=15= 中的 List
中显示它们].
代码如下:
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
。
这里出了什么问题?
请告诉我。
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) {
您可以使用 Firebase 查询来限制侦听器下载的数据。
query.orderByChild("someChild").limitToLast(1).addChildEventListener(...
@Blundell 具有解决您问题的洞察力。我只是想向您建议与 addValueEventListener
类似的方法。
The value event listener will fire once for the initial state of the
data, and then again every time the value of that data changes.
您需要从 onClick
函数中移出 firebase 查询。所以你的查询可能看起来像这样..
// 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) { }
});
}
现在写一个函数来显示 AlertDialog
中的 ListView
// 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();
}
});
@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();
}
}
...
...
});
}
});
使用 valueEventListener
或 addChildEventListener
时设置限制。像这样,
int limit = 100;
databaseRef.child("chats").limitToLast(limit).addValueEventListener(listener);
并且在完成与 firebase 相关的工作后,请始终移除侦听器。像这样,
databaseRef.child("chats").limitToLast(limit).removeEventListener(listener);
谢谢。
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
/**
检索项目列表或侦听对项目列表的添加。对每个现有的 child 触发一次此回调,然后每次将新的 child 添加到指定路径时再次触发此回调。传递给侦听器的 DataSnapshot 包含新的 child 数据。
**/
}
@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(child事件监听器);
使用 ChildEventListener onChildAdded 是根据您在该节点中的 child 调用的。表示您的代码运行 3 次,因此对话框出现 3 次。
这就是问题所在
所以解决方案是:
While using a ChildEventListener is the recommended way to read lists of data, there are situations where attaching a ValueEventListener to a list reference is useful.
Attaching a ValueEventListener to a list of data will return the entire list of data as a single DataSnapshot, which you can then loop over to access individual children.
Even when there is only a single match for the query, the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result:
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());
// ...
}
});
在调用 .addChildEventListener() 之前创建并显示 AlertDialog
然后在下载适当的数据后,在 addChildEventListener 内部调用 notifyDatasetChanged()。不要在 addChildEventListener
中创建 AlertDialog
嗯,none上面的答案确实有帮助,虽然Linxy的答案是正确的,但我在解决问题后才看到它。
移出所有代码并只写这一行:alertDialog.show();
inside 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();
}
});
无论如何,我要感谢所有回答这个问题的人。
和平。
我正在从 FirebaseDatabase
中获取一些数据,然后将它们放入 array
中,然后尝试在自定义 [=15= 中的 List
中显示它们].
代码如下:
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
。
这里出了什么问题?
请告诉我。
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) {
您可以使用 Firebase 查询来限制侦听器下载的数据。
query.orderByChild("someChild").limitToLast(1).addChildEventListener(...
@Blundell 具有解决您问题的洞察力。我只是想向您建议与 addValueEventListener
类似的方法。
The value event listener will fire once for the initial state of the data, and then again every time the value of that data changes.
您需要从 onClick
函数中移出 firebase 查询。所以你的查询可能看起来像这样..
// 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) { }
});
}
现在写一个函数来显示 AlertDialog
ListView
// 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();
}
});
@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();
}
}
...
...
});
}
});
使用 valueEventListener
或 addChildEventListener
时设置限制。像这样,
int limit = 100;
databaseRef.child("chats").limitToLast(limit).addValueEventListener(listener);
并且在完成与 firebase 相关的工作后,请始终移除侦听器。像这样,
databaseRef.child("chats").limitToLast(limit).removeEventListener(listener);
谢谢。
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
/**
检索项目列表或侦听对项目列表的添加。对每个现有的 child 触发一次此回调,然后每次将新的 child 添加到指定路径时再次触发此回调。传递给侦听器的 DataSnapshot 包含新的 child 数据。
**/
}
@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(child事件监听器); 使用 ChildEventListener onChildAdded 是根据您在该节点中的 child 调用的。表示您的代码运行 3 次,因此对话框出现 3 次。
这就是问题所在 所以解决方案是:
While using a ChildEventListener is the recommended way to read lists of data, there are situations where attaching a ValueEventListener to a list reference is useful.
Attaching a ValueEventListener to a list of data will return the entire list of data as a single DataSnapshot, which you can then loop over to access individual children.
Even when there is only a single match for the query, the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result:
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());
// ...
}
});
在调用 .addChildEventListener() 之前创建并显示 AlertDialog
然后在下载适当的数据后,在 addChildEventListener 内部调用 notifyDatasetChanged()。不要在 addChildEventListener
中创建 AlertDialog嗯,none上面的答案确实有帮助,虽然Linxy的答案是正确的,但我在解决问题后才看到它。
移出所有代码并只写这一行:alertDialog.show();
inside 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();
}
});
无论如何,我要感谢所有回答这个问题的人。
和平。