I am using the Firestore database and need to fetch some data from it. How do I make the function await for the data before returning the list?
fun getExercise(bodyPart: String): MutableList<String> {
val db = Firebase.firestore
val exercisesList = mutableListOf<String>()
val exercise = db.collection("exercises")
val query = exercise.whereEqualTo("body-part", bodyPart)
query.get().addOnSuccessListener { result ->
for(temp in result) {
exercisesList.add(temp.id)
Log.d(TAG, "${temp.id} => ${temp.data}")
}
}
.addOnFailureListener { exception ->
Log.w(TAG, "Error getting documents: ", exception)
}
return exercisesList
}
I know I need to use .await()
but I am new to Kotlin and can't make it work.
CodePudding user response:
I see 2 possible options:
1. Change your code in order to call another function with the result instead of returning the result
fun getExercise(bodyPart: String) {
val db = Firebase.firestore
val exercisesList = mutableListOf<String>()
val exercise = db.collection("exercises")
val query = exercise.whereEqualTo("body-part", bodyPart)
query.get().addOnSuccessListener { result ->
for(temp in result) {
exercisesList.add(temp.id)
Log.d(TAG, "${temp.id} => ${temp.data}")
}
// Call another function with the result:
anotherFunction(exercisesList)
}.addOnFailureListener { exception ->
Log.w(TAG, "Error getting documents: ", exception)
}
}
2. Implement Kotlin Coroutines
This option might be a little more complex than the first one for someone who's new to the language, as you'd need to understand the concept of Kotlin Coroutines.
- Start by adding the Coroutines dependency to your build.gradle file:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}
- Change your function to become a
suspend
function:
suspend fun getExercise(bodyPart: String): MutableList<String> {
// ...
}
- Use the
await()
extension function to fetch the result:
suspend fun getExercise(bodyPart: String): MutableList<String> {
val db = Firebase.firestore
val exercisesList = mutableListOf<String>()
val exercise = db.collection("exercises")
val query = exercise.whereEqualTo("body-part", bodyPart)
try {
val result = query.get().await()
for (temp in result) {
exercisesList.add(temp.id)
Log.d(TAG, "${temp.id} => ${temp.data}")
}
return exercisesList
} catch (e: Exception) {
Log.w(TAG, "Error getting documents: ", exception)
return emptyList() // returning an empty list in case the fetch fails
}
}
- Use a Coroutine scope when making a call to your
suspend
function:
// If you're calling from an Activity/Fragment, you can use the
// lifecycleScope from the lifecycle-runtime-ktx library
//
// If you're calling from a ViewModel, consider using the
// viewModelScope from the lifecycle-viewmodel-ktx library
//
// See https://d.android.com/topic/libraries/architecture/coroutines#dependencies
// for more details
lifecycleScope.launch { // Coroutine Scope
val exercises: MutableList<String> = getExercise("arms")
// use the list
}
More resources: