这是异步 Web API 的经典问题。您现在无法返回尚未加载的内容。换句话说,您不能简单地将places 列表作为方法的结果返回,因为由于onComplete 函数的异步行为,它总是为空的。根据您的连接速度和状态,数据可用可能需要几百毫秒到几秒钟的时间。
但不仅 Cloud Firestore 会异步加载数据,几乎所有现代其他 Web API 都会这样做,因为获取数据可能需要一些时间。但是让我们举个简单的例子,通过在代码中放置一些日志语句,以更清楚地了解我在说什么。
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 中的输出将是:
在附加监听器之前!
附加监听器后!
onComplete 函数内部!
这可能不是您所期望的,但它准确地解释了为什么您的地点列表在返回时是空的。
大多数开发人员的最初反应是尝试“修复”这个asynchronous behavior,我个人建议不要这样做。 Here 是 Doug Stevenson 写的一篇很棒的文章,我强烈推荐你阅读。
此问题的快速解决方案是仅在 onComplete 函数内使用地点列表:
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:
interface MyCallback {
fun onCallback(value: List<String>)
}
然后你需要创建一个函数来实际从数据库中获取数据。此方法应如下所示:
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 接口的实例作为参数传递,如下所示:
readData(object: MyCallback {
override fun onCallback(value: List<String>) {
Log.d("TAG", list.size.toString())
}
})
如果您使用的是 Kotlin,请查看其他 answer。