继续从回调中挂起函数

rim*_*mes 3 android kotlin kotlin-coroutines coroutinescope

我使用 firestore 作为后端数据库,保存数据如下所示:

suspend fun uploadDataToFirestore() {
  val firestore = Firebase.firestore
  var batch = firestore.batch
 
 -- fill batch with data --

  batch.commit().addOnCompleteListener {
    if (it.isSuccessful) {
      Timber.d("Successfully saved data")
     
      doAdditionalSuspendingStuff()
            
    } else {
      Timber.d("error at saving data: ${it.exception}")     
    }
}
 
Run Code Online (Sandbox Code Playgroud)

问题出在内部,onCompleteListener因为我无法调用额外的挂起函数。有没有办法从onCompleteListenerbut 内部调用挂起函数,以便它们仍然附加到相同的作用域,因为我不希望函数在执行uploadDataToFirestore之前完成。doAdditionalSuspendingStuff()

小智 6

您可以使用kotlinx-coroutines-play-services工件,其中包含一小组用于在协程和任务 API 之间进行转换的实用程序(您也会在其他 Play 相关库中找到它们)。

您应该能够用挂起扩展函数替换基于回调的 API ( addOnCompleteListener()) Task.await()

suspend fun uploadDataToFirestore() {
    val firestore = Firebase.firestore
    val batch = firestore.batch

    try {
        batch.commit().await() // Suspend the coroutine while uploading data.

        Timber.d("Successfully saved data")
        doAdditionalSuspendingStuff()
    } catch (exception: Exception) {
        Timber.d("error at saving data: $exception")     
    }
}
Run Code Online (Sandbox Code Playgroud)

await()还返回一个未包装的结果(TinTask<T>)。

在底层,它使用suspendCancellableCoroutineTask<T>.addCompleteListener()转换为挂起函数。源代码可在此处获取。