Firebase 实时数据库等待数据被检索
Firebase Realtime Database wait until the data is retrieved
我有一个包含我的 Firebase 实时数据库的键的地图,我想检索相应的键数据并将其放入结果数据列表中。如何按顺序执行循环?基本上,阻止 Firebase 侦听器直到它获得结果,然后才迭代到循环中的下一个键。
fun functionA() {
val resultFileDataList = List<DataSnapshot>()
for ((key, value) in filesMap) {
val dbRef = database.child("files").child(key)
dbRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(dataSnapshot: DataSnapshot) {
resultFileDataList.add(dataSnapshot)
}
})
}
callFunctionB() // call this function only after all the data in the loop above is retrieved
}
我尝试了 runBlocking {}
但没有成功。
既然您使用的是 Kotlin,那么最简单的解决方案就是使用 Kotlin Coroutines。这样,您可以使用挂起函数并为每个读取操作调用等待。为此,请查看以下文章:
如果您需要 , then you should consider using kotlinx-coroutines-play-services, case in which you can use awaitAll() 功能。
这是一种方法:
suspend fun functionA() = suspendCoroutine<List<DataSnapshot>>{ continuation ->
val resultFileDataList = mutableListOf<DataSnapshot>()
for ((key, value) in filesMap) {
val dbRef = database.child("files").child(key)
dbRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(dataSnapshot: DataSnapshot) {
resultFileDataList.add(dataSnapshot)
if(resultFileDataList.size == fileMaps.size){
continuation.resume(resultFileDataList)
}
}
})
}
}
然后你可以像这样在任何地方调用函数:
CoroutineScope(Dispatchers.IO).launch {
val dataSnapshotList = functionA()
functionB(dataSnapshotList)
}
请记住,最好使用以下方法将协程绑定到 activity 的生命周期:
lifecycleScope.launch(Dispatchers.IO) {
val dataSnapshotList = functionA()
functionB(dataSnapshotList)
}
注:
这基本上会等待所有数据更改,以便触发 onDataChanged()
并在添加最后一个文件时,继续协程和 returns 值。根据用户的行为,这可能需要很长时间才能完成,因为即使其中一个文件没有更改,协程也不会恢复。
此外,如果为一个文件触发了 onCancelled()
,这将永远不会完成。因此,如果您绝对确定 onDataChanged()
将对所有文件触发,请使用它。否则,实施某种超时功能以恢复不完整的数据。
你可以通过使用任务来实现它。 Tasks.whenall() 将等待所有任务完成。
fun functionA() {
val taskList = mutableListOf<Task<DataSnapshot>>()
val resultFileDataList = List<DataSnapshot>()
for ((key, value) in filesMap) {
val databaseReferenceTask: Task<DataSnapshot> = database.child("files").child(key).get()
taskList.add(databaseReferenceTask)
val resultTask = Tasks.whenAll(taskList)
resultTask.addOnCompleteListener {
for (task in taskList) {
val snapshotKey: String? = task.result.key
val snapShotValue = task.result
}
callFunctionB()
}
}
}
我有一个包含我的 Firebase 实时数据库的键的地图,我想检索相应的键数据并将其放入结果数据列表中。如何按顺序执行循环?基本上,阻止 Firebase 侦听器直到它获得结果,然后才迭代到循环中的下一个键。
fun functionA() {
val resultFileDataList = List<DataSnapshot>()
for ((key, value) in filesMap) {
val dbRef = database.child("files").child(key)
dbRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(dataSnapshot: DataSnapshot) {
resultFileDataList.add(dataSnapshot)
}
})
}
callFunctionB() // call this function only after all the data in the loop above is retrieved
}
我尝试了 runBlocking {}
但没有成功。
既然您使用的是 Kotlin,那么最简单的解决方案就是使用 Kotlin Coroutines。这样,您可以使用挂起函数并为每个读取操作调用等待。为此,请查看以下文章:
如果您需要
这是一种方法:
suspend fun functionA() = suspendCoroutine<List<DataSnapshot>>{ continuation ->
val resultFileDataList = mutableListOf<DataSnapshot>()
for ((key, value) in filesMap) {
val dbRef = database.child("files").child(key)
dbRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(dataSnapshot: DataSnapshot) {
resultFileDataList.add(dataSnapshot)
if(resultFileDataList.size == fileMaps.size){
continuation.resume(resultFileDataList)
}
}
})
}
}
然后你可以像这样在任何地方调用函数:
CoroutineScope(Dispatchers.IO).launch {
val dataSnapshotList = functionA()
functionB(dataSnapshotList)
}
请记住,最好使用以下方法将协程绑定到 activity 的生命周期:
lifecycleScope.launch(Dispatchers.IO) {
val dataSnapshotList = functionA()
functionB(dataSnapshotList)
}
注:
这基本上会等待所有数据更改,以便触发 onDataChanged()
并在添加最后一个文件时,继续协程和 returns 值。根据用户的行为,这可能需要很长时间才能完成,因为即使其中一个文件没有更改,协程也不会恢复。
此外,如果为一个文件触发了 onCancelled()
,这将永远不会完成。因此,如果您绝对确定 onDataChanged()
将对所有文件触发,请使用它。否则,实施某种超时功能以恢复不完整的数据。
你可以通过使用任务来实现它。 Tasks.whenall() 将等待所有任务完成。
fun functionA() {
val taskList = mutableListOf<Task<DataSnapshot>>()
val resultFileDataList = List<DataSnapshot>()
for ((key, value) in filesMap) {
val databaseReferenceTask: Task<DataSnapshot> = database.child("files").child(key).get()
taskList.add(databaseReferenceTask)
val resultTask = Tasks.whenAll(taskList)
resultTask.addOnCompleteListener {
for (task in taskList) {
val snapshotKey: String? = task.result.key
val snapShotValue = task.result
}
callFunctionB()
}
}
}