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

查看:12
本文介绍了作为 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:

在附加监听器之前!

附加监听器后!

onComplete 函数内部!

Inside onComplete function!

这可能不是您所期望的,但它准确地解释了为什么您的地点列表在返回时为空.

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

大多数开发人员的最初反应是尝试修复"这种异步行为,我个人建议反对它.这里是一篇优秀的文章由道格·史蒂文森 (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,请查看其他答案.

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

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

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