【问题标题】:How to use results from a Firebase query to ultimately populate a ListView in Android Studio如何使用 Firebase 查询的结果最终在 Android Studio 中填充 ListView
【发布时间】: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() 方法内将项目添加到ArrayListusernames”。

第二个问题:我还能如何存储从我的 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 实现,可以为您处理。
  • 你可能应该提出一个新问题并删除后续问题的伙伴
  • 另外:如果我的答案有错别字,请在此处修复。我们不介意修复我们在 StackOverflow 上的帖子。如果您的解决方案有很大不同,请将其添加为您自己的答案。
  • 非常酷!不知道我可以编辑别人的帖子。我很欣赏这些提示,因为我在这里还很新,而且一般都在编码。有这样的社区真是令人鼓舞!

标签: java android android-listview android-studio firebase


【解决方案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");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多