Это классическая проблема с асинхронными веб-API. Нельзя сейчас вернуть то, что еще не было загружено. Другими словами, вы не можете просто вернуть список places в результате метода, потому что он всегда будет пустым из-за асинхронного поведения функции onComplete. В зависимости от скорости и состояния вашего соединения может пройти от нескольких сотен миллисекунд до нескольких секунд, прежде чем эти данные станут доступными.
Но не только Cloud Firestore загружает данные асинхронно, как и почти все другие современные веб-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, что я лично не рекомендую. Здесь написана отличная статья Дуга Стивенсона, который я настоятельно рекомендую вам прочитать.
Быстрое решение этой проблемы - использовать список мест только внутри функции 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)
}
}
}
Видите ли, у нас больше нет возвращаемого типа. В конце просто вызовите функцию readData() в своей функции onCreate и передайте экземпляр интерфейса MyCallback в качестве аргумента, подобного этому:
readData(object: MyCallback {
override fun onCallback(value: List<String>) {
Log.d("TAG", list.size.toString())
}
})
Если вы используете Kotlin, проверьте другой ответ.
person
Alex Mamo
schedule
30.07.2018