getContactsFromFirebase()方法返回一个空列表 [英] getContactsFromFirebase() method return an empty list

查看:78
本文介绍了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.

这意味着到您return 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:

在附加侦听器之前

Before attaching listener

附加监听器后

在onDataChange

In onDataChange

这可能不是您期望输出的顺序.您可以看到在之后行,在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()方法返回一个空列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆