Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
543 views
in Technique[技术] by (71.8m points)

firebase - 如何通过Kotlin中的函数从Firestore数据库返回列表?(How to return a list from Firestore database as a result of a function in Kotlin?)

I'm building an app for a friend and I use Firestore.

(我正在为朋友构建应用程序,并且使用Firestore。)

What I want is to display a list of favorite places but for some reason, the list is always empty.

(我要显示的是最喜欢的地方列表,但是由于某种原因,该列表始终为空。)

在此处输入图片说明

I cannot get the data from Firestore.

(我无法从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;
}

If I try to print, let's say the size of the list in onCreate function, the size is always 0.

(如果我尝试打印,假设onCreate函数中列表的大小始终为0。)

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

I can confirm Firebase is successfully installed.

(我可以确认Firebase已成功安装。)

What am I missing?

(我想念什么?)

  ask by Jane Ashley translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a classic issue with asynchronous web APIs.

(这是异步Web API的经典问题。)

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.

(换句话说,您不能简单places由于方法的结果而返回places列表,因为由于onComplete函数的异步行为,该列表将始终为空。)

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.

(根据您的连接速度和状态,可能需要数百毫秒到几秒钟的时间才能获得该数据。)

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.

(但是,不仅Cloud Firestore异步加载数据,几乎所有其他现代Web API也会异步加载数据,因为获取数据可能需要一些时间。)

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;
}

If we run this code will, the output in your logcat will be:

(如果我们运行此代码,您的logcat中的输出将是:)

Before attaching the listener!

(连接听众之前!)

After attaching the listener!

(附加监听器后!)

Inside onComplete function!

(里面的onComplete函数!)

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

(这可能不是您所期望的,但恰恰说明了为什么返回时您的地点列表为空。)

The initial response for most developers is to try and "fix" this asynchronous behavior , which I personally recommend against it.

(对于大多数开发人员而言,最初的响应是尝试并“修复”这种asynchronous behavior ,我个人对此建议这样做。)

Here is an excelent article written by Doug Stevenson that I'll highly recommend you to read.

(是道格·史蒂文森(Doug Stevenson)撰写的精彩文章,我强烈建议您阅读。)

A quick solve for this problem would be to use the places list only inside the onComplete function:

(快速解决此问题的方法是仅在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
        }
    }
}

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.

(您需要创建自己的回调以等待Firestore向您返回数据。)

To achieve this, first you need to create an interface like this:

(为此,首先需要创建一个如下interface :)

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)
        }
    }
}

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:

(最后,只需在onCreate函数中调用readData()函数,然后将MyCallback接口的实例作为参数传递如下:)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...