firebase - 如何作为 Kotlin 中函数的结果从 Firestore 数据库返回列表?

标签 firebase kotlin google-cloud-firestore kotlin-coroutines

我正在为 friend 构建应用,并且使用 Firestore。我想要的是显示一个最喜欢的地方的列表,但由于某种原因,该列表总是空的。

enter image description here

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

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。

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

我可以确认 Firebase 已成功安装。 我错过了什么?

最佳答案

这是异步 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 中的输出将是:

Before attaching the listener!

After attaching the listener!

Inside onComplete function!

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

大多数开发人员的最初 react 是尝试“修复”此异步行为,我个人建议不要这样做。 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 接口(interface)的实例作为参数传递,如下所示:

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

如果你使用的是Kotlin,请查看其他answer .

关于firebase - 如何作为 Kotlin 中函数的结果从 Firestore 数据库返回列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55080286/

相关文章:

android - 在 Android 上的 Kotlin 中,如何在一个或每个循环期间在不可变列表中发生空指针异常?

loops - 在 kotlin 循环中继续 n 次

javascript - 如何对分页项目执行 "go back"

firebase - 按计划自动备份整个 firestore 数据库的首选方法是什么,以便进行手动恢复

android - 无法在 iOS [Firebase] 中接收通知

Firebase REST API 与 JS 客户端库

android - Firebase 平台实时数据库的命名约定

ios - 无法从控制台编辑iOS应用的链接行为

android - Jetpack Compose - 用图案绘制弧线

android - 如何使用用户定义的文档 ID 创建 Firebase Firestore 文档?