getcontactsfromfirebase()方法返回空列表

yiytaume  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(217)
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() 方法返回空列表。你能帮帮我吗?

roqulrg3

roqulrg31#

从firebase异步加载数据。因为从服务器获取数据可能需要一些时间,所以主要的android代码会继续,firebase会调用您的 onDataChange 当数据可用时。
这意味着当你 return mContactsFromFirebase 它还是空的。最简单的方法是放置一些日志语句:

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");

运行此代码时,它将打印:
在附加侦听器之前
附加侦听器后
在ondatachange中
这可能不是您期望的输出顺序。正如您可以看到的,在调用回调之前 onDataChange . 这就解释了为什么您返回的列表是空的,或者(更准确地说)当您返回它时它是空的,并且只在以后被填充。
有几种方法可以处理这种异步加载。
最简单的解释是将所有返回列表的代码放入 onDataChange 方法。这意味着此代码仅在加载数据后执行。以最简单的形式:

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);
}

Kotlin:

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

现在可以将此接口的实现传递给 getContactsFromFirebase 方法:
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();
    }
  });
}

Kotlin:

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")
  }
});

Kotlin:

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

它不像同步加载数据那么简单,但它的优点是运行时不会阻塞主线程。
这个主题以前讨论过很多,所以我建议你也来看看这些问题:
这篇来自道格的博文
在firebase侦听器中设置singleton属性值(在这里我解释了在某些情况下如何获得同步数据加载,但通常不能)
返回一个对象android(我第一次使用log语句解释发生了什么)
是否可以从firebase同步加载数据?
https://stackoverflow.com/a/38188683 (道格展示了一种很酷但很复杂的使用 Task 带firebase数据库的api)
如何作为方法的结果返回datasnapshot值(从那里我借用了一些回调语法)

相关问题