I want to implement this code synchronously
but job.join
, deferred.await
, and firebase await
, not working.
Does anyone know a solution?
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")
}
Log order:
D/user-get: job-end
D/user-get: on-0-> addOnComplete
D/user-get: on->com.google.android.gms.tasks.zzw@5c0519d
deferred
and await
, and Task.whenAllComplete(tasks).addOnCompleteListener { ~~~ }.await
are also same log result.
really appreciate Alex! the below is the code that I mentioned at comment
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
}
Is it proper way to use both firebase and coroutine?
it was executed as I expected
2
Answers
I think what you need to do is to not use
addOnCompleteListener
and useawait()
function on theTask
object instead:As I commented in an earlier question of yours, there is no need to launch a coroutine when you attach a listener. It’s one, or the other. When you call
Tasks#whenAllComplete(Task...<?> tasks
), the type of object that is returned isTask<List<Task<?>>
. This means that all the heavy work is done behind the scenes, in a different thread. So there is nothing that can block the main thread. When you attach a listener, it means that you’ll wait until the operation is complete, or fails with an exception. So you either get the request out of the coroutine or, as @Sergio mentioned in his answer, remove the listener and call await(). Please also note that this function is a suspend function and not a blocking function.Now, since this operation can raise an exception, is recommended to add the following lines of code inside a method, perhaps in a repository class, and use a try-catch together with Kotlin flow:
And inside a ViewModel class launch a coroutine and collect the result:
So most likely you might consider converting the list of DocumentSnapshot objects into a list of custom objects of yours. That being said, an even simpler solution, would be not to iterate but to call QuerySnapshot#toObjects(Class clazz):
I have written an article called:
Where I explain step by step how you can achieve that. Here is the corresponding repo. And here is a line of code where I do the the conversion.