EN VI

Kotlin - Calling Fire-And-Forget Methods - Which Scope?

2024-03-10 23:30:06
How to Kotlin - Calling Fire-And-Forget Methods - Which Scope?

I'm overriding the analyze() method of ImageAnalysys.Analyzer, so I want it to execute and return as soon as possible. I've got a method that I want to call from analyze(), which will manipulate some member variables and eventually want to notify a View that it has something new to show, but it is lengthy. Thus, I'd like to queue that method for execution but return to analyze() immediately.

I was using GlobalScope.launch { fireAndForgetMethod() } and that (apparently) works as intended, but I get the 'delicate API' warning and the help popup suggests it is not a good idea. I've seen MainScope().launch {} and mentions of viewModelScope and lifecycleScope. But then I've seen articles such as How to: Grpc fire and forget async api call in Kotlin which suggest that even just using fire-and-forget is discouraged.

I've recently learned about JavaScript's async, await and Promise architecture so I have a vague idea of what Kotlin's suspend might do, but I think I need a more intelligent answer - code may seem to work, but be dodgy.

  1. If I mark fireAndForgetMethod() as suspend and make a normal call to that from analyze(), will it return immediately from the call and is this the right technique? I don't need an answer from the method.

  2. If that's not the way, what scope should I use for launch {}?

  3. Is there another (approved) way to do lengthy operations without blocking analyze()? (The data required for the long method comes from analyze(), so somehow that's where I need to trigger it). What about a worker thread, and setting a flag in the thread to say 'GO!'?

Solution:

  1. You will also have to mark analyze() as suspend method. A normal call to fireAndForgetMethod() will then wait until the method is finished, before continuing.
  2. Ideally, you should use coroutineScope(Dispatchers.IO | DEFAULT | MAIN) depending on the type of work you do in fireAndForgetMethod(). Although, when the scope is finished, it will wait until all its tasks are finished too. i.e., This would first print "Async", before it gets to the "Test":
runBlocking { // Only needed if your function is not already marked as `suspend`
    coroutineScope {
        launch {
            delay(5000)
            println("Async")
        }
    }
}
println("Test")
  1. You can use threads. You can use some background worker if your system/framework (e.g., Android, Spring, etc.) supports that.

If you truly want the function to be executed in the background, without having any scope that could await it, using GlobalScope should be fine.

Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login