Kotlin Android中Firebase Storage顺序上传的错误监听方法
问题
在Kotlin Android应用中,我需要将文件列表上传至Firebase Storage,但并发上传过多文件时会偶发OOM崩溃,因此打算改为顺序上传(每次仅上传一个文件,等待完成后再继续下一个)。
我尝试使用fileRef.putFile(fileUri).await().storage.downloadUrl.await().toString()来等待上传成功后的下载URL,成功时代码运行正常,但上传出错时这段代码会无限等待。
请问:
- 如何在等待成功结果的同时捕获错误并终止等待?
await()是否是实现顺序上传的正确方式?
以下是原异步上传代码(已简化):
val fileUri = Uri.fromFile(file) val fileRef = Firebase.storage.reference.child("$BLAH/$userID/${Uuid}/${fileUri.lastPathSegment}") fileRef.putFile(fileUri).addOnSuccessListener { fileRef.downloadUrl.addOnSuccessListener { Firebase.firestore.collection(BLAH).document(BLAH) .set( blinkybill.toCloud(BLAH, it.toString()), SetOptions.merge() ) .addOnSuccessListener { updateStatus(CloudSyncStatus.STARTED) CoroutineScope(Dispatchers.IO).launch { blahDao.updateBlah( blahEntity.copy( fileUploaded = true ) ) } } .addOnFailureListener { e -> logger("Error uploading the URL to Firebase. Not the one I care about right now") updateStatus(CloudSyncStatus.ERROR) } } }.addOnFailureListener { logger("THIS IS THE UPLOAD ERROR I WANT TO CATCH WHILE WAITING FOR DOWNLOAD") updateStatus(CloudSyncStatus.ERROR) }
解决方案
1. await()是正确的实现方式
Firebase的Task类支持Kotlin协程的await()扩展(需依赖kotlinx-coroutines-play-services库),用它实现顺序上传是合理的,既能避免回调地狱,又天然支持顺序执行逻辑。
2. 捕获错误终止等待的方法
await()在Task执行失败时会抛出ExecutionException(包裹原始错误),只需用**try-catch块**包裹上传逻辑,就能捕获错误并终止等待,不会出现无限挂起的情况。
3. 优化后的顺序上传代码示例
假设你有文件列表fileList,可在协程中遍历列表逐个处理上传:
// 建议使用绑定生命周期的Scope,比如ViewModel的viewModelScope,避免内存泄漏 viewModelScope.launch(Dispatchers.IO) { updateStatus(CloudSyncStatus.STARTED) fileList.forEachIndexed { index, file -> try { val fileUri = Uri.fromFile(file) val fileRef = Firebase.storage.reference.child("$BLAH/$userID/${Uuid}/${fileUri.lastPathSegment}") // 上传文件并等待完成 fileRef.putFile(fileUri).await() // 获取下载URL并等待结果 val downloadUrl = fileRef.downloadUrl.await().toString() // 更新Firestore(用await替代回调,统一处理错误) Firebase.firestore.collection(BLAH).document(BLAH) .set(blinkybill.toCloud(BLAH, downloadUrl), SetOptions.merge()) .await() // 更新本地数据库 blahDao.updateBlah(blahEntity.copy(fileUploaded = true)) logger("第${index+1}个文件上传成功") } catch (e: Exception) { // 捕获所有上传/更新过程中的错误 when (e) { is ExecutionException -> logger("上传失败:${e.cause?.message}") else -> logger("未知错误:${e.message}") } updateStatus(CloudSyncStatus.ERROR) // 可选:遇到错误是否终止后续上传?若要终止,直接return // return@launch } } // 所有文件上传完成 updateStatus(CloudSyncStatus.COMPLETED) }
4. 关键注意事项
- 依赖配置:确保在
build.gradle中添加协程依赖:implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3" - Scope选择:不要使用
GlobalScope,优先用viewModelScope(ViewModel中)或lifecycleScope(Activity/Fragment中),避免内存泄漏。 - 错误处理粒度:可根据需求拆分
try-catch,比如单独捕获上传文件、获取URL、Firestore更新的错误,做精细化处理。 - 内存优化:顺序上传已避免并发过多导致的OOM,若仍有内存问题,可优化文件读取逻辑,或在每次上传后手动触发垃圾回收(不推荐依赖,仅作临时缓解)。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

