【问题标题】:Android Firebase Firestore query returns empty results from function, but the same code works when included directlyAndroid Firebase Firestore 查询从函数返回空结果,但直接包含时相同的代码有效
【发布时间】:2022-02-21 23:52:50
【问题描述】:

我在 Studio 中遇到了 Firebase 查询问题。 我正在尝试抽象一个简单的查询以获取存储在集合中的对象列表(在我的情况下为“用户”) 我想创建一个存储在类中的函数,该函数可以被项目中的每个片段调用。 但是我没有找到任何方法可以做到这一点,重复相同的指令是唯一的方法吗? 这是一个例子

db.collection("users") //get all the users
.get()
.addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       if(task.getResult() != null) {
           for (QueryDocumentSnapshot document : task.getResult()) { 
                usersList.add(document.toObject(User.class));
            } else {
                Log.w(LOGIN, "Error getting documents.", task.getException());
            }
        });

我每次需要这些代码行时都会编写它们,但我想创建一个返回 List 的方法,如下例所示:

public static List<User> getUsers(FirebaseFirestore db) {
  List<User> usersList = new ArrayList<>();

  db.collection("users") //get all the users
  .get()
  .addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
       if(task.getResult() != null) {
           for (QueryDocumentSnapshot document : task.getResult()) { 
                usersList.add(document.toObject(User.class));
            } else {
                Log.w(LOGIN, "Error getting documents.", task.getException());
            }
        });
    } else {
      //error
    }
  return usersList;
}

【问题讨论】:

    标签: java android firebase google-cloud-firestore


    【解决方案1】:

    数据是从 Firestore(和大多数现代云 API)异步加载的,因为这可能需要一些时间。主代码不会在这段时间内阻塞应用程序,而是继续执行。然后当数据可用时,您的 addOnCompleteListener 回调将使用该数据执行。


    查看这一点的最简单方法是在代码中添加一些适当的日志记录:

    public static List<User> getUsers(FirebaseFirestore db) {
      Log.i(LOGIN, "Starting getUsers");
    
      db.collection("users") //get all the users
      .get()
      .addOnCompleteListener(task -> {
        Log.i(LOGIN, "Got data");
      })
      Log.i(LOGIN, "Returning from getUsers");
    }
    

    当你运行这段代码时,你会得到以下输出:

    开始获取用户

    从 getUsers 返回

    得到数据

    这可能不是您期望的顺序,但它完全解释了为什么调用 getUsers 的代码永远看不到数据:当您的 return usersList 运行时,数据尚未加载,usersList.add(document.toObject(User.class)) 已从未被调用过。


    解决方案总是一样的:任何需要数据库数据的代码,必须要么在完成回调中,要么从那里调用,要么通过其他方式同步。

    一个简单的例子是创建一个自定义回调函数:

    public interface GetUsersCallback {
        void onCallback(List<User> users);
    }
    

    然后你将它传递给getUsers,它可以在从数据库中获取并处理结果后调用它:

    public static void getUsers(FirebaseFirestore db, GetUsersCallback callback) {
                                                   // ?
      List<User> usersList = new ArrayList<>();
    
      db.collection("users") //get all the users
      .get()
      .addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
           if(task.getResult() != null) {
               for (QueryDocumentSnapshot document : task.getResult()) { 
                    usersList.add(document.toObject(User.class));
                } else {
                    Log.w(LOGIN, "Error getting documents.", task.getException());
                }
            });
            callback(usersList); // ?
        }
    }
    

    然后你可以像这样使用它:

    getUsers(new GetUsersCallback() {
        @Override
        public void onCallback(List<User> users) {
            Log.i(LOGIN, "Found "+users.size()+" users");
        }
    });
    

    在处理云 API 时,异步加载数据非常普遍,但当您第一次遇到它时,它也相当令人困惑。我建议阅读其中一些答案以了解更多信息:

    【讨论】:

      猜你喜欢
      • 2013-08-13
      • 2020-07-08
      • 1970-01-01
      • 2015-08-04
      • 1970-01-01
      • 2019-10-28
      • 2011-04-11
      • 2018-01-07
      • 1970-01-01
      相关资源
      最近更新 更多