这是异步web API的classic 问题.您现在无法退回尚未加载的内容.换句话说,您不能简单地将places
列表作为方法的结果返回,因为由于onComplete
函数的异步行为,它将始终为空.根据您的连接速度和状态,数据可用可能需要几百毫秒到几秒钟.
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", "连接听者之后!");
return list;
}
If we run this code will, the output in your logcat will be:
Before attaching the listener!
连接听者之后!
Inside onComplete function!
This is probably not what you expected, but it explains precisely why your places list is empty when returning it.
对于大多数开发人员来说,最初的react 是try "修复"这个asynchronous behavior
,我个人建议不要这么做."Here"是道格·史蒂文森写的一篇出色的文章,我强烈推荐你阅读.
这个问题的一个快速解决方法是只在onComplete
函数中使用places list:
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)
}
}
}
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个.