FireStore Tasks.whenAllComplete结合协程同步执行问题求助
问题描述
1. 协程与Firebase Tasks同步执行异常
尝试用job.join、deferred.await以及Firebase的await实现代码同步执行,但日志始终显示job-end先输出,Tasks的addOnComplete回调后执行,未达到预期效果。
相关代码:
CoroutineScope(Dispatchers.Main).launch { val job = launch { Tasks.whenAllComplete(tasks) .addOnCompleteListener { Log.d("user-get", "on-0-> addOnComplete") tasks.forEach { task -> val snapshot = task.result Log.d("user-get", "on->"+ task.toString()) snapshot.documents.forEach { docs.add(it) } } } } job.join() Log.d("user-get", "job-end") }
日志顺序:
D/user-get: job-end D/user-get: on-0-> addOnComplete D/user-get: on->com.google.android.gms.tasks.zzw@5c0519d
尝试deferred+await、Task.whenAllComplete(tasks).addOnCompleteListener { ... }.await等写法,日志顺序仍一致。
2. 确认Firebase与协程结合的写法是否正确
编写了checkNickName挂起函数,执行符合预期,但想确认该写法是否为Firebase与协程结合的正确方式:
override suspend fun checkNickName(nickName: String): Results<Int> { lateinit var result : Results<Int> fireStore.collection("database") .document("user") .get() .addOnCompleteListener { document -> if (document.isSuccessful) { val list = document.result.data?.get("nickNameList") as List<String> if (list.contains(nickName)) result = Results.Exist(1) else result = Results.No(0) //document.getResult().get("nickNameList") } else { } }.await() return result }
解决方案
1. 修复协程与Tasks同步执行问题
当前代码中,job内部仅完成了回调注册操作,Tasks.whenAllComplete(tasks).addOnCompleteListener(...)会立即执行完毕,异步任务仍在后台运行,因此job快速结束,job.join()提前放行导致job-end先输出。
正确写法是去掉addOnCompleteListener,直接用Firebase Task的await()方法挂起协程,直到任务完成:
CoroutineScope(Dispatchers.Main).launch { val job = launch { // await()会挂起协程,直到所有任务完成并返回结果 val allTasksResult = Tasks.whenAllComplete(tasks).await() Log.d("user-get", "on-0-> addOnComplete") allTasksResult.forEach { task -> val snapshot = task.result Log.d("user-get", "on->"+ task.toString()) snapshot.documents.forEach { docs.add(it) } } } job.join() Log.d("user-get", "job-end") }
调整后日志顺序会变为:
D/user-get: on-0-> addOnComplete D/user-get: on->com.google.android.gms.tasks.zzw@5c0519d D/user-get: job-end
2. 优化checkNickName函数的写法
原函数虽能运行,但存在两处隐患:
lateinit var result未处理任务失败场景,会导致未初始化就返回的异常;- else分支未处理任务失败的情况(如网络错误、权限问题)。
规范写法是直接在await()后处理结果,无需addOnCompleteListener,同时完善错误处理:
override suspend fun checkNickName(nickName: String): Results<Int> { return try { val document = fireStore.collection("database") .document("user") .get() .await() // 协程挂起直到任务完成 if (document.isSuccessful) { val list = document.result.data?.get("nickNameList") as? List<String> ?: emptyList() if (list.contains(nickName)) { Results.Exist(1) } else { Results.No(0) } } else { // 返回任务失败对应的结果 Results.Error(-1) } } catch (e: Exception) { // 捕获网络异常等情况 Results.Error(-2) } }
该写法既利用了协程的挂起特性,又规避了lateinit的风险,是Firebase与协程结合的正确方式。
内容的提问来源于stack exchange,提问作者tring yuo
相关产品推荐
相关产品推荐

