Hi, I have one suspend fun in kotlin which is call...
# coroutines
s
Hi, I have one suspend fun in kotlin which is calling api and before we return we need to trigger one more method which will keep running in background for saving some heavy stuff(saving some images or files for some data entity) in local db even after returning from this method. How can i achieve that? Is there any way we can return from this method but somehow wait for someBackgroundWork to get finished in background, or some other way?
Hi, this is code for understanding the flow
Copy code
//just for simulation of client
fun main() {
    println("Before Api call is started")
    runBlocking {
        someApiCallMethod()
    }
    println("work is finished")

}

//Suppose this is kmm module method, This will be called from client side
suspend fun someApiCallMethod(): String {
    println("Api call is started")

    //simulate api call
    delay(2000)

    /* Before we return we need to trigger one method
      which will keep running in background for saving some heavy stuff in local db even after returning from this method,
      How can i achieve that? How can i return from this method but somehow wait for someBackgroundWork to get finished */

    someBackgroundWorkTest() //if i use this method, it gets cancelled when we return from this method
    //someBackgroundWork2Test() //and if we use this method, it makes this method wait here to get it finished and it returns after this work is finished

    println("returned from someApiCallMethod Api call")
    return "someDataFromApi"

}


suspend fun someBackgroundWorkTest() {
    val job = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
        //simulate work
        delay(4000)
        println("someBackgroundWork is finished")
    }

    job.invokeOnCompletion {
        println("i m cancelled due to : ${it?.cause}")
    }

}

suspend fun someBackgroundWork2Test() {
    coroutineScope {
        launch(<http://Dispatchers.IO|Dispatchers.IO>) {
            //simulate work
            delay(4000)
            println("someBackgroundWork is finished")
        }
    }
}
r
you can create your own coroutine scope, bound to some lifecycle (depending on your use case), so to modify your example:
Copy code
val someBackgroundScope = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>)

// ...

suspend fun someBackgroundWork2Test() {
    someBackgroundScope.launch {
        //simulate work
        delay(4000)
        println("someBackgroundWork is finished")
    }
}
this will launch the coroutine in the custom scope, and return immediately. Note that: • this basically breaks structured concurrency (but it sounds like you want this). If anything fails in
someBackgroundWork
, this does not get propagated back to the original caller of the
someApiCallMethod
, so be sure to properly handle exceptions / errors in the background task yourself • be sure to manage the lifecycle of the
someBackgroundScope
coroutine scope yourself, so call
someBackgroundScope.cancel()
when the lifecycle ends (so e.g. in case of an Android Activity, when the activity is destroyed) (to make this work in your example code, make sure to add a
Thread.sleep
with a long enough timeout at the end of the
main
method, because otherwise the jvm shuts down before the background work is finished)
s
Thanks @Riccardo Lippolis But i tried this approach already in someBackgroundWorkTest , but It also require some waiting time there to get that method finished as u mentioned before we switch activity in android. Lets suppose in android app if we use this approach(suppose from kmm module), and when our kmm someApiCall method returns, then suppose we switch activity then how we will manage, then activity related viewmodel will be cleared where we will be calling this method and this method will also be cancelled. In this scenario how we can code this?
r
In this case, the idea is to bind the lifecycle of the
someBackgoundScope
coroutine scope to something that outlives your activity. I'm not an Android developer, so not sure about the correct terminology, but I'm sure there's something like background workers or a service that you can create/use that has a longer lifespan than an activity?
s
Yes, we can bind to application scope in android, that outlives activity. But i was thinking of something to do from kotlin multiplatform side for both android and iOS, But i think that can not be possible i was thinking it wrong way, after all coroutine will be eventually bound to some lifecycle at all, So i think this case will be handled more by client side (android or ios) but not in kmm. Thanks