skip to Main Content

I have the below function which is completely 2 task asynchronously to upload data to Firebase. I need the 2nd function to return the documentId of new document created in Firebase and once done the main function 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
}

2

Answers


  1. 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
      }
    
    1. If you do not want to use job.join, then we can modify code as
      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
      }
    
    Login or Signup to reply.
  2. Add .join()

    CoroutineScope(Dispatchers.IO).launch {
        supervisorScope {
    
            try {
                async {
                    firstFunctionToUploadAysnchronouslyToFirebase()
                }.await()
    
    
                async {
                    documentId = secondFunctionToUploadAsynchronouslyToFirebase()
                }.await()
    
            } catch (error: Exception) {
                throw error
            }
        }
    }.join()
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search