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

标签 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 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 - 如何从 Firestore 数据库返回列表作为 Kotlin 中函数的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51594772/

相关文章:

ios - Firebase MLKit 文本识别错误

firebase realtimeDB 同时连接?

android - 无法从 Google 相册应用中选取图片

android - "Immersive Mode"安卓应用。所有文档均已弃用

kotlin - 奇怪的kotlin checkNotNullParameter错误

java - 如何将 Google Core API 依赖项添加到 Android Studio Gradle 项目?

ios - 如何从 UIImagePickerController 获取图像的 NSURL?用于上传到 Firebase

firebase - 在 firestore 中存储全局应用设置的最佳实践

firebase - 函数的返回类型为 'Future<String>' 但不以 return 语句结尾

firebase - 为什么有时imageUrl被保存在Cloud Firestore数据库中而有时却不保存