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

spand

10/11/2018, 6:13 AM
Is this correct and the most concise way of having cleanup in the implement CoroutineScope pattern?
Copy code
class Activity : CoroutineScope {
    var job = Job()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default + job

    init {
        val workJob = launch(start = CoroutineStart.LAZY) {
            // Doing stuff
            delay(5000)
        }
        launch(start = CoroutineStart.ATOMIC) {
            try {
                workJob.join()
            } finally {
                println("Cleaning up")
            }
        }
    }

    fun destroy() {
        job.cancel()
    }
}
g

gildor

10/11/2018, 6:15 AM
Actually this should be enough:
Copy code
class Activity : CoroutineScope {
   override val coroutineContext = Dispatchers.UI + Job()


  override fun onDestroy() {
      coroutineContext.cancel()
  } 
}
Not sure what code in
init
block should show, doesn’t make a lot of sense for me with all those ATOMIC and additional lazy launch But maybe I don’t see some important usecase
s

spand

10/11/2018, 6:18 AM
I need to perform an action once the job is done.. either by cancellation or completion.
Preferably within the scope of Job so
job.join()
will return after cleanup
g

gildor

10/11/2018, 6:23 AM
Why not just use
invokeOnCompletion
?
s

spand

10/11/2018, 6:24 AM
Cant launch new suspendable functions
g

gildor

10/11/2018, 6:24 AM
inside of invokeOnCompletion?
s

spand

10/11/2018, 6:24 AM
yes
g

gildor

10/11/2018, 6:24 AM
I see
in this case you probably need to coroutines yeah
Also curious about clean approach for this But can you close resources just using onDestroy? Because if your function that cleanups resources is suspendable it also will be cancelled Maybe more clear and stable solution would be just runBlocking in onDestroy or even invokeOnCompletion, otherwise you in trap of async closing operations I of course don’t know everything about your case, so hard to tell will it be better or not
s

spand

10/11/2018, 6:38 AM
The ATOMIC ensures the cleanup operation will run even if the parent is cancelling
g

gildor

10/11/2018, 6:38 AM
yes, but what about suspend functions that you call there
you said that you need suspend function and you cannot use invokeOnComplete
s

spand

10/11/2018, 6:39 AM
Good question. I would assume they inherit that status so they cannot be cancelled either
g

gildor

10/11/2018, 6:39 AM
as I understand ATOMIC will guarantee only that such coroutine will be started, but if you call any suspend function such function will be just cancelled (I may be wrong, I just thought that it works like that)
I don’t think that atomic make coroutine non cancellable
it’s just about way how you start coroutine, atomic cannot be cancelled before actual start
But again, it’s just my understanding
You can use NonCancellable context for some cases, but not sure that it wat you whant here]
s

spand

10/11/2018, 6:48 AM
A quick test seems to confirm that any
launch
will just be cancelled. Setting the NonCancellable context gives the appropriate behaviour.
g

gildor

10/11/2018, 6:49 AM
Why you just cannot wrap your resource with try/finally in your original “worker” launch, you just shouldn’t acquire resource outside of try, as I understand this should work
s

spand

10/11/2018, 6:49 AM
I can call additional suspend methods which I think is enough in my case albeit a bit fragile to rely on
Yeah that would be simpler. I wonder why that got extracted in the first place 😉
g

gildor

10/11/2018, 7:05 AM
Yeah, try to use:
Copy code
launch {
            try {
                // Doing stuff
               delay(5000)
            } finally {
                println("Cleaning up")
            }
        }
But again, depends on what is “cleaning up”, it cannot be cancellable suspend function, only blocking or something with NonCancellable context
d

Dico

10/11/2018, 1:29 PM
What about launching the cleanup coroutine in global scope?
Or just without the same parent?
k

kingsley

10/11/2018, 1:49 PM
You can use
withContext(NonCancellable) { ... }
in finally I believe But yea, Andrey already hit on all the points to consider
2 Views