如何在 firebase 数据库中使用 kotlin 协程
Posted
技术标签:
【中文标题】如何在 firebase 数据库中使用 kotlin 协程【英文标题】:How to use kotlin coroutines in firebase database 【发布时间】:2019-08-07 19:43:11 【问题描述】:我正在尝试使用 firestore 和协程访问聊天室。
fun getOwner()
runBlocking
var de = async(Dispatchers.IO)
firestore.collection("Chat").document("cF7DrENgQ4noWjr3SxKX").get()
var result = de.await().result
但我得到这样的错误:
E/androidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.map_fetchuser_trest, PID: 19329
java.lang.IllegalStateException: Task is not yet complete
at com.google.android.gms.common.internal.Preconditions.checkState(Unknown Source:29)
at com.google.android.gms.tasks.zzu.zzb(Unknown Source:121)
at com.google.android.gms.tasks.zzu.getResult(Unknown Source:12)
at com.example.map_fetchuser_trest.model.Repository$getOwner$1.invokeSuspend(Repository.kt:53)
如何获取聊天文件?当我使用下面的 origin api 时,我可以访问聊天室文档。
firestore.collection("Chat").document(
"cF7DrENgQ4noWjr3SxKX"
).get().addOnCompleteListener task ->
if (task.isSuccessful)
val chatDTO = task.result?.toObject(Appointment::class.java)
【问题讨论】:
【参考方案1】: val db = FirebaseFirestore.getInstance()
override suspend fun saveBinToDB(bin: Bin): Result<Unit>
lateinit var result:Result<Unit>
db.collection("bins")
.add(bin)
.addOnSuccessListener documentReference ->
Log.d(TAG, "DocumentSnapshot written with ID: $documentReference.id")
result = Result.Success(Unit)
.addOnFailureListener e ->
Log.w(TAG, "Error adding document", e)
result = Result.Error(Exception())
.await()
return result
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.7"
【讨论】:
当,这就是我要找的。有很多关于使用 Kotlin 与 Firestore 交互的示例,并且大多数(如果不是全部)使用await()
函数。该 jetbrains 库的实现正是您所需要的。【参考方案2】:
第一个代码sn-p中runBlocking..
的用法如下:runBlocking
函数阻塞来执行参数lambda代码(而lambda代码会在里面挂起)。它给人的感觉更少。
您可能希望使用launch..
函数启动一个协程,并使用withContext(Dispatchers.Main)..
让该块在 UI 线程中执行,例如显示获取的结果。你也可以在你的活动类中实现CoroutineScope
。
第一步 - 您需要将 Firebase API 调用转换为挂起函数。可以使用 suspendCoroutine..
函数来完成(在 kotlinx.coroutines 库中还有更多函数,例如 suspendCancellableCoroutine..
。
有一个与 Google Play 服务集成的库,提供对 Firebase 的支持https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services
【讨论】:
【参考方案3】:Task
是人们等待的东西,但你将它包裹在另一层 async
中。删除async
:
fun getOwner()
runBlocking
var de = firestore.collection("Chat").document("cF7DrENgQ4noWjr3SxKX").get()
var result = de.await().result
但是,通过使用runBlocking()
,您已经在自己的脚下开了一枪,并且编写了只是正式使用异步 API 而没有好的效果的阻塞代码。
要真正从中受益,你必须拥有一个
suspend fun getOwner() = firestore
.collection("Chat")
.document("cF7DrENgQ4noWjr3SxKX")
.get()
.await()
.result
和launch
在你调用它的地方有一个协程:
launch
val owner = getOwner()
// update the GUI
这假设您从一个 CoroutineScope
的对象调用 launch
。
【讨论】:
如果我删除“async”,那么suspend func中的“.await()”函数是从哪里来的? 您需要在org.jetbrains.kotlinx:kotlinx-coroutines-play-services 中定义的Task.await()
。
不可能使用相同的概念(协同程序中的挂起函数)并且还具有firestore实时功能,对吧?我问这个是因为答案中显示的代码是一个很好的例子,说明了在我们必须多次查询集合并合并由于 Firestore 查询限制而导致的结果。但是,再一次,有没有办法在保持实时功能的同时做呢?或者,有没有办法在不存在回调地狱问题的情况下进行多次调用?
有人能告诉我await()
函数是在哪个调度程序中调用的吗? Dispatchers.IO
和 Dispatchers.Main
之间调用 .await() 是否有任何性能差异
@Andrew await()
的行为与任何其他可挂起函数一样,并在当前调度程序中执行。它在哪里执行与运行任务本身的代码在哪里执行无关。正如它的名字所说,它除了等待什么都不做。因此,您应该让它使用Main
调度程序。以上是关于如何在 firebase 数据库中使用 kotlin 协程的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 Firebase 身份验证的情况下保护 Firebase 存储? (下一个)
如何在新的 Firebase 控制台中检查数据库和存储使用情况