使用FireBase / FireStore在Java的内部函数中访问数据

时间:2018-10-30 01:31:02

标签: java android firebase google-cloud-firestore

我正在使用Google的FireStore后端编写一个Android应用程序。从官方文档中获取Firestore集合中所有文档的代码如下:

db.collection("cities")
    .get()
    .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                    Log.d(TAG, document.getId() + " => " + document.getData());
                }
            } else {
                Log.d(TAG, "Error getting documents: ", task.getException());
            }
        }
    });

以上代码输出到Log.d(...)的地方,我想让我的程序将document.getData()调用的结果添加到内部类/方法外部可访问的ArrayList上。我不确定执行此操作的最佳方法是什么。尝试更改return onComplete方法的返回类型会产生错误。在这种方法中是否有访问元素的标准方法?

声明变量并尝试在类中进行变异也是不可能的,除非该变量是最终变量,否则将使问题无济于事。

2 个答案:

答案 0 :(得分:1)

  

我想让我的程序将document.getData()调用的结果添加到内部类/方法外部可访问的ArrayList中。

在这种情况下,如果您使用的是模型类,则应使用toObject()方法,并在YourModelClass中添加ArrayList类型的对象,如下所示:

if (task.isSuccessful()) {
    List<YourModelClass> list = new ArrayList<>();
    for (QueryDocumentSnapshot document : task.getResult()) {
        YourModelClass yourModelClass = document.toObject(YourModelClass.class);
        list.add(yourModelClass);

        //Do what you need to do with your list
    }
}

如您所见,我建议您在回调中使用YourModelClass对象的列表。这是因为onComplete()方法具有异步行为,您不能简单地在回调之外使用该列表,因为它始终为空。

  

尝试更改return的onComplete方法的返回类型会产生错误。

更改方法的返回类型不会给您带来错误,但是结果始终是一个空列表。您现在无法返回尚未加载的内容。快速解决此问题的方法是,仅在onComplete()方法内部使用该对象列表,就像我上面已经写过的那样;或者,如果您想在外部使用它,我建议您从在 post 中,我已经说明了如何使用自定义回调来完成此操作。您也可以查看此 video 以获得更好的理解。

答案 1 :(得分:1)

这是一个异步调用(它会启动一个后台进程来执行Firebase查询,一旦完成,它就会执行您的onComplete侦听器),因此您不能期望在此之后立即拥有数据进行数据库调用。例如,如果您的函数看起来像

void getData() {
    final List<MyData> list = new ArrayList<>();

    db.collection("cities")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        Log.d(TAG, document.getId() + " => " + document.getData());
                        list.add(new MyData(document.getData()));
                    }
                } else {
                    Log.d(TAG, "Error getting documents: ", task.getException());
                }
            }
        });

    Log.d(TAG, "List size = " + list.size()); // will print 0
    // list will be empty here, the firebase call will take hundreds 
    // to thousands of milliseconds to complete
}

您需要对程序进行结构设计,使其可以等待数据到达。您可以通过几种方法来执行此操作。一种方法是让list成为由onComplete侦听器填充的类成员(然后,您必须构造程序以处理随机时间传入的数据)。

另一种方法是让数据处理程序例程使用ArrayList并对其执行某些操作。获取所有数据后,可以从onComplete侦听器调用此方法。例如:

void getData() {
    db.collection("cities")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    List<MyData> list = new ArrayList<>();
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        Log.d(TAG, document.getId() + " => " + document.getData());
                        list.add(new MyData(document.getData()));
                    }
                    processData(list);
                } else {
                    Log.d(TAG, "Error getting documents: ", task.getException());
                }
            }
        });
}

void processData(List<MyData> data) {
    // do stuff with the data, or make a copy, or otherwise share it
    // with the rest of your program
}