使用 Kotlin 协程与 Firebase

7

我在我的应用程序中使用Kotlin协程,并选择Firebase作为数据库和存储的选项。探索Firebase后,我意识到它所有的API都是异步的,并且异步调用的结果以回调形式返回,而摆脱回调是我在应用程序中使用Kotlin协程的主要原因。

这是我编写的代码,用于将文件上传到Firebase云存储,但它会出现“任务尚未完成”的错误。

private suspend fun saveImage(filePath: String): String? {
        val storage = FirebaseStorage.getInstance("gs://myapp-9a648.appspot.com/")
        val storageRef = storage.reference
        val file = Uri.fromFile(File(filePath))
        val imageRef = storageRef.child("images/${file.lastPathSegment}")
        return withContext(Dispatchers.IO) {
            imageRef.putFile(file).snapshot.storage.downloadUrl.result.toString()
        }
    }

E/AndroidRuntime: 致命异常: 主线程 进程:pk.com.kotlinapp,PID:7491 java.lang.IllegalStateException: 任务尚未完成 at com.google.android.gms.common.internal.Preconditions.checkState(源位置未知) at com.google.android.gms.tasks.zzu.zzb(源位置未知) at com.google.android.gms.tasks.zzu.getResult(源位置未知) at prk.com.kotlinapptest.DatabaseManager$saveImage$2.invokeSuspend(DatabaseManager.kt:28) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
有没有办法在不在成功回调中获取下载URL的情况下将文件上传到Firebase Cloud Storage并返回下载URL?

2
https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services - Doug Stevenson
@DougStevenson:谢谢,我会试一下。 - Parag Kadam
检查我的答案在这里使用Kotlin协程将多个照片上传到Firebase - MohamedHarmoush
1个回答

14

kotlinx-coroutines-play-services 提供了 await 扩展函数,允许等待任务完成,例如:

...
dependencies {
  ...
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.1"
}
return withContext(Dispatchers.IO) {
    imageRef
        .putFile(file)
        .await() // await() instead of snapshot
        .storage
        .downloadUrl
        .await() // await the url
        .toString()
}

1
@coroutineDispatcher 是的,它可以。但问题是如何摆脱回调函数。我认为上面的代码更易读,特别是当您同时处理一堆远程调用时。 - Valeriy Katkov
对我来说有效的代码是:imageRef .putFile(file) .await() .storage .downloadUrl .await() .toString() - Jon
@Johnnie90 谢谢您的纠正!我已经修正了答案。 - Valeriy Katkov
如果有多个异常被抛出,你该如何捕获它们? - SNM
Firebase BoM 31.0.0开始,kotlinx-coroutines-play-services库已经包含在firebase-storage-ktx中,因此您无需手动添加该依赖项。 await()应该可以直接使用。 - Rosário Pereira Fernandes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接