Background
I'm having problems in migrating from the simple (deprecated) AsyncTask and Executors to Kotlin Coroutines on Android
The problem
I can't find how I can perform the basic things I could have done on AsyncTask and even on Executors using Kotlin Coroutines.
In the past, I could choose to cancel a task with and without thread interruption. Now for some reason, given a task that I create on Coroutines, it's only without interruption, which means that if I run some code that has even "sleep" in it (not always by me), it won't be interrupted.
I also remember I was told somewhere that Coroutines is very nice on Android, as it automatically cancel all tasks if you are in the Activity. I couldn't find an explanation of how to do it though.
What I've tried and found
For the Coroutines task (called Deferred according to what I see) I think I've read that when I create it, I have to choose which cancellation it will support, and that for some reason I can't have them both. Not sure if this is true, but I still wanted to find out, as I want to have both for best migration. Using AsyncTask, I used to add them to a set (and remove when cancelled) so that upon Activity being finished, I could go over all and cancel them all. I even made a nice class to do it for me.
This is what I've created to test this:
class MainActivity : AppCompatActivity() {
val uiScope = CoroutineScope(Dispatchers.Main)
val bgDispatcher: CoroutineDispatcher = Dispatchers.IO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadData()
}
private fun loadData(): Job = uiScope.launch {
Log.d("AppLog", "loadData")
val task = async(bgDispatcher) {
Log.d("AppLog", "bg start")
try {
Thread.sleep(5000L) //this could be any executing of code, including things not editable
} catch (e: Exception) {
Log.d("AppLog", "$e")
}
Log.d("AppLog", "bg done this.isActive?${this.isActive}")
return@async 123
}
//simulation of cancellation for any reason, sadly without the ability to cancel with interruption
Handler(mainLooper).postDelayed({
task.cancel()
}, 2000L)
val result: Int = task.await()
Log.d("AppLog", "got result:$result") // this is called even if you change orientation, which I might not want when done in Activity
}
}
build gradle file:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"
The questions
- Is it possible on Coroutines to have a task that I can cancel with and without thread interruption?
- What should be added to make this work, so that when the Activity dies (orientation change, for example), it would be auto-cancelled (with the choice of with or without interruption) ? I guess I could use a similar solution as I had for AsyncTask, but I remember I was told there is a nice way to do it for Coroutines too.