I have the below function which is completing 2 tasks asynchronously to upload data to Firebase Firestore. The 2nd function is returning the documentId of the new document created in Firestore and once done, the main function profileLiked
returns this documentId so I can use it elsewhere. However, the return function is completing before the Firebase upload async functions have run and hence is returning an empty string. How can I fix this?
suspend fun profileLiked(): String {
var documentId: String = ""
CoroutineScope(Dispatchers.IO).launch {
supervisorScope {
try {
async {
firstFunctionToUploadAysnchronouslyToFirebase()
}.await()
async {
documentId = secondFunctionToUploadAsynchronouslyToFirebase()
}.await()
} catch (error: Exception) {
throw error
}
}
}
//this return function is getting called first and returning the empty string instead of the documentId result from secondFunctionToUploadAsynchronouslyToFirebase()
return documentId
}
There is no issue with above code and it is doing what it intended.
If you need documentId which is returned from the secondFunctionToUploadAsynchronouslyToFirebase
, then you need to wait on parent coroutine before you return the documentId.
Additional info added as comments.
suspend fun profileLiked(): String {
var documentId: String = ""
val job = CoroutineScope(Dispatchers.IO).launch { // This will create a new coroutine
supervisorScope {
try {
async { // another async coroutine within parent coroutine
firstFunctionToUploadAysnchronouslyToFirebase()
}
async { // another async coroutine within parent coroutine
documentId = secondFunctionToUploadAsynchronouslyToFirebase()
}
} catch (error: Exception) {
throw error
}
}
}
job.join() // This will wait until all children of parent coroutines are executed.
return documentId
}
suspend fun profileLiked(): String {
var documentId: String = ""
supervisorScope { // Ref: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html
try {
val c1 = async(Dispatchers.Default) { // another async coroutine within parent coroutine, you can skip using `Dispatchers.Default`
firstFunctionToUploadAysnchronouslyToFirebase()
}
val c2 = async(Dispatchers.Default) { // another async coroutine within parent coroutine, you can skip using `Dispatchers.Default`
documentId = secondFunctionToUploadAsynchronouslyToFirebase()
}
listOf(c1, c2).awaitAll()
} catch (error: Exception) {
throw error
}
}
return documentId
}