如何使用 Firebase 查询的结果最终在 Android Studio 中填充 ListView
Posted
技术标签:
【中文标题】如何使用 Firebase 查询的结果最终在 Android Studio 中填充 ListView【英文标题】:How to use results from a Firebase query to ultimately populate a ListView in Android Studio 【发布时间】:2015-12-07 06:53:06 【问题描述】:我发现我的 ListView 在应用程序运行时没有更新,因为适配器是在 Firebase 查询发生之前设置的。
第一个问题:有没有为查询完成设置监听器?这样我可以在那里设置adapter
。我知道一些 Firebase 方法会自动生成 onComplete()
/onSuccess()
侦听器。
出于调试目的,我可以通过重新输入onResume()
来触发对 ListView 的更新。这是我收到错误消息的地方:
The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(16908298, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
据我了解,如果我在ArrayAdapter
中使用usernames
,则无法在onChildAdded()
方法内将项目添加到ArrayList
“usernames
”。
第二个问题:我还能如何存储从我的 Firebase 查询返回的值并使用这些值最终填充 ListView 而无需直接从“后台线程”更改其内容?
我的尝试:
public class EditFriendsActivity extends AppCompatActivity
protected ArrayList<String> usernames = new ArrayList<>();
@Override
protected void onResume()
super.onResume();
Firebase usernameRef = ref.child("users");
Query queryRef = usernameRef.orderByKey();
queryRef.addChildEventListener(new ChildEventListener()
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
String username = (String) dataSnapshot.child("username").getValue();
usernames.add(username);
Log.v(TAG, usernames + "");
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s)
Log.v(TAG, "Inside ChildChanged");
@Override
public void onChildRemoved(DataSnapshot dataSnapshot)
Log.v(TAG, "Inside ChildRemoved");
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s)
Log.v(TAG, "Inside ChildMoved");
@Override
public void onCancelled(FirebaseError firebaseError)
Log.e(TAG, firebaseError.getMessage());
AlertDialog.Builder builder = new AlertDialog.Builder(EditFriendsActivity.this);
builder.setTitle(R.string.error_title)
.setMessage(firebaseError.getMessage())
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
);
// Array adapter
ArrayAdapter<String> adapter = new ArrayAdapter<>(
EditFriendsActivity.this,
android.R.layout.simple_list_item_multiple_choice,
usernames);
mFriendsList.setAdapter(adapter);
更新的代码:修复了每次从标记答案和清除列表中听者的错字。
Firebase userRef = ref.child("users");
userRef.addListenerForSingleValueEvent(new ValueEventListener()
@Override
public void onDataChange(DataSnapshot dataSnapshot)
usernames.clear(); // Clear list before updating
for (DataSnapshot child : dataSnapshot.getChildren())
String username = (String) child.child("username").getValue();
usernames.add(username);
Log.v(TAG, usernames + "");
跟进问题Here
【问题讨论】:
我稍后会写一个答案,但你可能想看看github.com/firebase/FirebaseUI-Android。这个库有一个 FirebaseListAdapter 实现,可以为您处理。 你可能应该提出一个新问题并删除后续问题的伙伴 另外:如果我的答案有错别字,请在此处修复。我们不介意修复我们在 *** 上的帖子。如果您的解决方案有很大不同,请将其添加为您自己的答案。 非常酷!不知道我可以编辑别人的帖子。我很欣赏这些提示,因为我在这里还很新,而且一般都在编码。有这样的社区真是令人鼓舞! 【参考方案1】:有没有为查询完成设置监听器?这样我就可以在那里设置适配器。我知道一些 Firebase 方法会自动生成
onComplete()
/onSuccess()
侦听器。
Firebases 将数据从后端同步到您的应用程序。因此,与具有请求/响应流的传统数据库不同,Firebase 查询并没有真正完成。这就是为什么在FirebaseUI library 中我们保持一个开放的侦听器并通知 ListView 任何更改。
也就是说:如果你只想从一个位置加载数据一次,你可以使用addSingleValueEventListener
:
queryRef.addListenerForSingleValueEvent(new ValueEventListener()
@Override
public void onDataChange(DataSnapshot snapshot)
for (DataSnapshot child: snapshot.getChildren())
String username = (String) child.child("username").getValue();
usernames.add(username);
ArrayAdapter<String> adapter = new ArrayAdapter<>(
EditFriendsActivity.this,
android.R.layout.simple_list_item_multiple_choice,
usernames);
mFriendsList.setAdapter(adapter);
@Override
public void onCancelled(FirebaseError firebaseError)
Log.e(TAG, firebaseError.getMessage());
);
上面可能有错别字,但这是它的大致要点。
【讨论】:
我怀疑我对你编写的每个循环的解释。这是我的镜头“对于快照中的每个节点,获取它的子节点(在我的情况下,/users 的子节点将是 /users/username 和 /users/email)并在每个节点上执行 .child("username").getValue();。 "快照不是我的参考中所有节点的集合吗?如果是这样,为什么我们需要执行 getChildren()?你能告诉我它是怎么读的吗? 您正在响应child_added
事件,因此您会收到每个孩子的电话。我听了一个value
事件,它让所有的孩子都一口气。这就是为什么我需要一个循环,而你不需要。
您介意看看我的后续问题吗?【参考方案2】:
您可以简单地使用查询
Query ref = FirebaseDatabase.getInstance().getReference()
.child("users").orderByChild("name");
【讨论】:
以上是关于如何使用 Firebase 查询的结果最终在 Android Studio 中填充 ListView的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Firebase 云 Firestore 中查询一个字段然后按另一个字段排序?
得到错误的结果:从 AngularJS 访问 api 并使用 NodeJS 从 firebase 查询结果时出现时区问题