本文介绍了getContactsFromFirebase() 方法返回一个空列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

public List<String> getContactsFromFirebase(){
    FirebaseDatabase.getInstance().getReference().child("Users")
            .addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                        Users user = snapshot.getValue(Users.class);
                        assert user != null;
                        String contact_found = user.getPhone_number();
                        mContactsFromFirebase.add(contact_found);
                        Log.i("Test", mContactsFromFirebase.toString());
                    }

                }
                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            });

    return mContactsFromFirebase;

}

我似乎无法找到错误.在上面的代码中,当我调用日志时,我从 mContactsFromFirebase 获取值,但 getContactsFromFirebase() 方法返回一个空列表.你能帮我吗?

I can't seem to find the error. In the code above, when I call the log, I get the values from mContactsFromFirebase, but the getContactsFromFirebase() method return an empty list. Could you help me please?

推荐答案

数据从 Firebase 异步加载.由于从服务器获取数据可能需要一些时间,因此主要的 Android 代码会继续,当数据可用时 Firebase 会调用您的 onDataChange.

Data is loaded from Firebase asynchronously. Since it may take some time to get the data from the server, the main Android code continues and Firebase calls your onDataChange when the data is available.

这意味着当您返回 mContactsFromFirebase 时,它仍然是空的.看到这一点的最简单方法是放置一些日志语句:

This means that by the time you return mContactsFromFirebase it is still empty. The easiest way to see this is by placing a few log statements:

System.out.println("Before attaching listener");
FirebaseDatabase.getInstance().getReference().child("Users")
    .addListenerForSingleValueEvent(new ValueEventListener() {
      @Override
      public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println("In onDataChange");
      }
      @Override
      public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
      }
    });
System.out.println("After attaching listener");

当你运行这段代码时,它会打印:

When you run this code, it will print:

附加监听器之前

附加监听器后

在 onDataChange

In onDataChange

这可能不是您期望的输出顺序.正如您所看到的行 after 回调在 onDataChange 之前被调用.这就解释了为什么你返回的列表是空的,或者(更准确地说)当你返回它时它是空的并且只有在以后才被填充.

That is probably not the order that you expected the output in. As you can see the line after the callback gets called before onDataChange. That explains why the list you return is empty, or (more correctly) it is empty when you return it and only gets filled later.

有几种方法可以处理这种异步加载.

There are a few ways of dealing with this asynchronous loading.

最简单的解释是将所有返回列表的代码放入onDataChange 方法.这意味着此代码仅在数据加载后执行.最简单的形式:

The simplest to explain is to put all code that returns the list into the onDataChange method. That means that this code is only execute after the data has been loaded. In its simplest form:

public void onDataChange(DataSnapshot dataSnapshot) {
    for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
        Users user = snapshot.getValue(Users.class);
        assert user != null;
        String contact_found = user.getPhone_number();
        mContactsFromFirebase.add(contact_found);
        System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
    }
}


但是还有更多方法,包括使用自定义回调(类似于 Firebase 自己的 ValueEventListener):

Java:

public interface UserListCallback {
  void onCallback(List<Users> value);
}

科特林:

interface UserListCallback {
  fun onCallback(value:List<Users>)
}

现在您可以将此接口的实现传递给您的 getContactsFromFirebase 方法:

Now you can pass in an implementation of this interface to your getContactsFromFirebase method:

Java:

public void getContactsFromFirebase(final UserListCallback myCallback) {
  databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
      for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
        Users user = snapshot.getValue(Users.class);
        assert user != null;
        String contact_found = user.getPhone_number();
        mContactsFromFirebase.add(contact_found);
        System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
      }
      myCallback.onCallback(mContactsFromFirebase);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
      throw databaseError.toException();
    }
  });
}

科特林:

fun getContactsFromFirebase(myCallback:UserListCallback) {
  databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(object:ValueEventListener() {
    fun onDataChange(dataSnapshot:DataSnapshot) {
      for (snapshot in dataSnapshot.getChildren())
      {
        val user = snapshot.getValue(Users::class.java)
        assert(user != null)
        val contact_found = user.getPhone_number()
        mContactsFromFirebase.add(contact_found)
        System.out.println("Loaded " + mContactsFromFirebase.size() + " contacts")
      }
      myCallback.onCallback(mContactsFromFirebase)
    }
    fun onCancelled(databaseError:DatabaseError) {
      throw databaseError.toException()
    }
  })

然后这样称呼它:

Java:

getContactsFromFirebase(new UserListCallback() {
  @Override
  public void onCallback(List<Users> users) {
    System.out.println("Loaded "+users.size()+" contacts")
  }
});

科特林:

getContactsFromFirebase(object:UserListCallback() {
  fun onCallback(users:List<Users>) {
    System.out.println("Loaded " + users.size() + " contacts")
  }
})

它不像同步加载数据那么简单,但这样做的好处是它可以在不阻塞主线程的情况下运行.

It's not as simple as when data is loaded synchronously, but this has the advantage that it runs without blocking your main thread.

这个话题之前已经讨论过很多,所以我建议你也看看其中的一些问题:

This topic has been discussed a lot before, so I recommend you check out some of these questions too:

  • this blog post from Doug
  • Setting Singleton property value in Firebase Listener (where I explained how in some cases you can get synchronous data loading, but usually can't)
  • return an object Android (the first time I used the log statements to explain what's going on)
  • Is it possible to synchronously load data from Firebase?
  • https://stackoverflow.com/a/38188683 (where Doug shows a cool-but-complex way of using the Task API with Firebase Database)
  • How to return DataSnapshot value as a result of a method? (from where I borrowed some of the callback syntax)

这篇关于getContactsFromFirebase() 方法返回一个空列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 05:33