为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

喵喔喔 2021-12-18 15:33:42
我正在使用 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内部类/方法之外的可访问对象。我不确定这样做的最佳方法是什么。尝试更改onComplete方法的返回类型会产生错误。在这样的方法中是否有访问元素的标准方法?声明一个变量并尝试在类中进行变异也是不可能的,除非变量是最终的,这与重点无关。
查看完整描述

2 回答

?
回首忆惘然

TA贡献1847条经验 获得超11个赞

这是一个异步调用(它启动一个后台进程来执行 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

}


查看完整回答
反对 回复 2021-12-18
?
四季花海

TA贡献1811条经验 获得超5个赞

我想让我的程序将 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()方法具有异步行为,您不能简单地在回调之外使用该列表,因为它始终为空。


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


更改方法的返回类型不会给您错误,但结果将始终是一个空列表。您现在无法返回尚未加载的内容。快速解决此问题的onComplete()方法是仅在方法内部使用该对象列表,正如我上面已经写的,或者如果您想在外部使用它,我建议您从这篇文章中查看我的 anwser 的最后一部分,其中我已经解释了如何使用自定义回调来完成。您也可以观看此视频以更好地理解。


查看完整回答
反对 回复 2021-12-18
  • 2 回答
  • 0 关注
  • 250 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号