Is it acceptable to save multiple job instances from separate coroutines. Let's say i want to run a couple coroutines at once in which they are unrelated and cannot happen in one coroutine but i want them to run parallel. In Android i should be saving the job instance so i can cancel the job in the onDestroy method. Would it be acceptable to save each job separately in a list or am i breaking some kind of rule. I know in RX they have Subscriptions why isn't there an equivalent in Kotlin Coroutines?
val jobList = arrayListOf<Job>()
fun startJob1() {
jobList.add(launch {
//do some work
})
fun startJob1() {
jobList.add(launch {
//do some other unrelated work
})
override fun onDestroy() {
super.onDestroy()
cancelAllActiveJobs(jobList)
}
Does this type of architecture make sense for coroutines?
You can manullay keep a list of Job
objects that you launch, but you can also use a parent-child Job hierarhy that is available out-of-the box to manage and keep the list of launched jobs easier.
So, first, instead of a list of jobs, you define a reference to a parent job:
val job = Job()
Then, every time you lauch a new coroutine you make it a child of this job:
fun startJob1() {
launch(job) { // make it a child
//do some work
}
}
fun startJob1() {
launch(job) { // make it a child
//do some other unrelated work
}
}
Finally, when you need to destroy your object and cancel all the jobs you just cancel the parent job.
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
The advantage of this apporoach is that the list of jobs is managed automatically. New coroutines can be launched and added to the parent job and when they complete they automatically remove themselves from the parent job.
You can read more in the corresponding section of the guide: https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#cancellation-via-explicit-job
That’s totally doable, and also nothing special. Look at this simple example which creates 100k jobs at once:
val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
For making the jobs cancellable, it must itself check if it has been cancelled from outside, which you can do with a loop over the activity state: while (isActive)
.
Here's an example with two jobs that are cancelled afterwards:
fun main(args: Array<String>) = runBlocking {
val startTime = System.currentTimeMillis()
val jobs = arrayListOf<Job>()
jobs += launch {
var nextPrintTime = startTime
var i = 0
while (isActive) { // check if still active
if (System.currentTimeMillis() >= nextPrintTime) {
println("Job1: Sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
//another job
jobs += launch {
while (isActive) { // check if still active
if (System.currentTimeMillis() >= 42) {
println("Job2: Sleeping 42 ...")
delay(500L)
}
}
}
delay(1300L) // delay a bit
println("main: Cancelling the sleeping job!")
jobs.forEach { it.cancelAndJoin() } // cancels the job and waits for its completion
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With