https://kotlinlang.org logo
#coroutines
Title
# coroutines
m

Melih Aksoy

07/22/2021, 9:29 AM
Hey all ! A question / discussion 🙂
Copy code
private var job: Job? = null
        set(value) {
            println("Setting value")
            field = value
        }

        job = lifecycleScope.launch() {
            println("Started")

            try {
                println("Try")
            } catch (e: CancellationException) {
                println("Catch")
            } finally {
                println("Finally")
            }
        }
prints
Copy code
Started
Try
Catch
Finally
Setting value
in order. Which means when using default coroutine start,
launch
returns
job
reference after contents are executed ( if execution is fast enough ). So there’s no guarantee when you’ll be handled
job
reference when you do the assignment. I didn’t find any mention of this in any docs, but I was expecting it to at least wait for reference to be handled before starting execution 🤔 This is probably troublesome in scenarios if you do an
if ( job != null ) return
check or similar ( clear in
finally
(
finally { job = null }
). You may end up
job
being assigned and not getting cleared. P.S. Using
CorotuineStart.LAZY
followed by
job?.start()
resolves this issue, I’m just asking if is this expected from default implementation 🤔 ?
w

wasyl

07/22/2021, 9:31 AM
This is Android, right? It might be because the default UI dispatcher uses an
immediate
scheduler, which executes the contents in-place if the coroutine is already started on the UI thread (unless a suspension point is hit)
👍 1
e

ephemient

07/22/2021, 9:32 AM
IIRC lifecycleScope uses Dispatchers.Main.immediate, so if you're already on the main thread it'll run immediately
*what Łukasz said
m

Melih Aksoy

07/22/2021, 9:32 AM
yeah, spot on it’s android 😄
e

ephemient

07/22/2021, 9:34 AM
also it seems bad to rely on that ordering anyway, if it's a multi-threaded dispatcher then there's still a chance the job could complete before you get done assigning the field
btw, why do you want to clear the job anyway?
m

Melih Aksoy

07/22/2021, 9:36 AM
yeah, I came up with snippet just for demonstration, to be honest I was mentally convinced that assignment should be done before execution 😄
to prevent multiple invokes of a function, eg
Copy code
fun something() {
   if ( job != null ) return

   job = launch { ... }
}
or cancelling previous job and reassigning ( for cases like refresh spam etc. )
it was working just fine until I hit the point where I return from the launch early by adding some checks, it turned into a race condition
e

ephemient

07/22/2021, 9:58 AM
var
-ectomy?
Copy code
val parentJob = Job(lifecycleScope.coroutineContext.job)

parentJob.cancelChildren() // cancel previous jobs without races
lifecycleScope.launch(parentJob) {
    // do work
}
5 Views