如何通过Kotlin中的函数从Firestore数据库返回列表? [英] How to return a list from Firestore database as a result of a function in Kotlin?

查看:131
本文介绍了如何通过Kotlin中的函数从Firestore数据库返回列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为朋友构建应用程序,并且使用Firestore.我要显示的是最喜欢的地点列表,但由于某种原因,该列表始终为空.

I'm building an app for a friend and I use Firestore. What I want is to display a list of favorite places but for some reason, the list is always empty.

我无法从Firestore获取数据.这是我的代码:

I cannot get the data from Firestore. This is my code:

fun getListOfPlaces() : List<String> {
    val places = ArrayList<String>()
    placesRef.get().addOnCompleteListener { task ->
        if (task.isSuccessful) {
            for (document in task.result) {
                val name = document.data["name"].toString()
                places.add(name)
            }
        }
    }
    return list;
}

如果我尝试打印,假设在onCreate函数中列表的大小始终为0.

If I try to print, let's say the size of the list in onCreate function, the size is always 0.

Log.d("TAG", getListOfPlaces().size().toString()); // Is 0 !!!

我可以确认Firebase已成功安装. 我想念什么?

I can confirm Firebase is successfully installed. What am I missing?

推荐答案

这是异步Web API的经典问题.您现在无法返回尚未加载的内容.换句话说,由于方法的结果,您不能简单地返回places列表,因为由于onComplete函数的异步行为,该列表将始终为空.根据您的连接速度和状态,可能需要几百毫秒到几秒钟的时间才能获得该数据.

This is a classic issue with asynchronous web APIs. You cannot return something now, that hasn't been loaded yet. With other words, you cannot simply return the places list as a result of a method because it will always be empty due the asynchronous behavior of the onComplete function. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.

但是,不仅Cloud Firestore异步加载数据,几乎所有其他现代Web API也会异步加载数据,因为获取数据可能需要一些时间.但是,让我们举个简单的例子,在代码中放置一些日志语句,以更清楚地了解我在说什么.

But not only Cloud Firestore loads data asynchronously, almost all of modern other web APIs do, since it may take some time to get the data. But let's take an quick example, by placing a few log statements in the code, to see more clearly what I'm talking about.

fun getListOfPlaces() : List<String> {
    Log.d("TAG", "Before attaching the listener!");
    val places = ArrayList<String>()
    placesRef.get().addOnCompleteListener { task ->
        if (task.isSuccessful) {
            Log.d("TAG", "Inside onComplete function!");
            for (document in task.result) {
                val name = document.data["name"].toString()
                places.add(name)
            }
        }
    }
    Log.d("TAG", "After attaching the listener!");
    return list;
}

如果我们运行此代码,您的logcat中的输出将为:

If we run this code will, the output in your logcat will be:

在附加侦听器之前!

Before attaching the listener!

附加监听器后!

内部onComplete函数!

Inside onComplete function!

这可能不是您所期望的,但恰恰说明了为什么返回时您的地点列表为空.

This is probably not what you expected, but it explains precisely why your places list is empty when returning it.

对于大多数开发人员而言,最初的响应是尝试修复"此asynchronous behavior,对此我个人建议反对. 此处是一篇出色的文章道格·史蒂文森(Doug Stevenson)撰写的文章,强烈建议您阅读.

The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against it. Here is an excelent article written by Doug Stevenson that I'll highly recommend you to read.

对此问题的快速解决方案是仅在onComplete函数内部使用位置列表:

A quick solve for this problem would be to use the places list only inside the onComplete function:

fun readData() {
    placesRef.get().addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val list = ArrayList<String>()
            for (document in task.result) {
                val name = document.data["name"].toString()
                list.add(name)
            }
            //Do what you need to do with your list
        }
    }
}

如果要在外面使用列表,则有另一种方法.您需要创建自己的回调以等待Firestore返回数据.为此,首先需要创建一个如下的interface:

If you want to use the list outside, there is another approach. You need to create your own callback to wait for Firestore to return you the data. To achieve this, first you need to create an interface like this:

interface MyCallback {
    fun onCallback(value: List<String>)
}

然后,您需要创建一个实际上从数据库获取数据的函数.此方法应如下所示:

Then you need to create a function that is actually getting the data from the database. This method should look like this:

fun readData(myCallback : MyCallback) {
    placesRef.get().addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val list = ArrayList<String>()
            for (document in task.result) {
                val name = document.data["name"].toString()
                list.add(name)
            }
            myCallback.onCallback(list)
        }
    }
}

瞧,我们没有任何返回类型了.最后,只需在onCreate函数中调用readData()函数,然后将MyCallback接口的实例作为这样的参数传递:

See, we don't have any return type anymore. In the end just simply call readData() function in your onCreate function and pass an instance of the MyCallback interface as an argument like this:

readData(object: MyCallback {
    override fun onCallback(value: List<String>) {
        Log.d("TAG", list.size.toString())
    }
})

如果您使用的是Kotlin,请检查其他 answer .

If you are using Kotlin, please check the other answer.

这篇关于如何通过Kotlin中的函数从Firestore数据库返回列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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