In this lecture, we discuss threads and in particular the use if Coroutines.
Your UI runs on a single thread to interact with the user -- this is the main thread. Therefore all code will run in this thread which might result in poor performance if you have a computationally intensive operation that could be run in another thread; for example, if your code is loading a file over the Internet you UI is completely blocked. This is not smart design.
The solution to this is simple: If you have computationally demanding functions or slow running operations the best solution if to run those tasks asynchronously from the UI threads.
We have discussed a number of AsyncTask examples in class:
CountDownTaskKotlin.zip
app to demonstrate how to use coroutines to handle thread programming. As discussed below this
simple example counts down in the background thread and posts the
current count to the UI thread. We disuss this in the notes below. The starter code can be found here.
ListViewOfProfsCoroutineKotlin.zip
updates the UI threads ListView by adding to the
adapter a list of names. You can find the starter code here.
The notes below relate specifically to the CountDownTaskKotlin example, but more generally to all the code examples listed above.
Some excellent references.
The demo app include in the lecture includes an activity that starts a Coroutine task to count down from 15, as shown below. Different text is rewritten out to the UI in different thread components of the UI and background thread, as shown below.
To create an app using coroutines, you need to add the Kotlin Coroutines dependencies in the Android project as below:
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:[current version]"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:[current version]
"
}
You can start a coroutine using CoroutineScope
, where you have three options for the context (or scope), in which your code will be executed:
CoroutineScope(IO).launch{
countDownTask()
}
We use coroutines in MyRuns:
For MyRuns3, you can use coroutines to operate a database. Again, if you did this in the main UI thread the user experience would be poor.
For MyRun5, you can use a coroutines to run the activity classifier at the background because it is computationally intensive and you do not want to block the UI thread.
Now let's look at the code for the coroutine demo app example.
The first snippet of code for doing the count down is shown in
countDownTask(), which is invoked on a worker thread. For any function
to be executed as coroutines, we use the "suspend" keywork when
defining the function. This is perpahs the first time you see the delay()
function. Delay() is similar to Thread.sleep()
but they are different in that delay() only delays that particular
coroutine in a thread. It will not interfere all the other coroutines
in that thread. Calling Thread.sleep() will sleep the entire thread (so
all the coroutines within that thread). So never call Thread.sleep
inside a coroutine.
private suspend fun countDownTask(){
for (i in 15 downTo 0) {
delay(800)
setTextOnMainThread(i.toString())
}
setTextOnMainThread("*DONE*")
}
Since we need to update the UI from the worker thread to show the
count, we create another function called setTextOnMainThread to handle
all the UI-related operations. In this example, we simply update the
TextView. Note that we switch the scope of code execution to the
main UI thread using withContext
. You can use CoroutineScope
too as they do the same thing.
private suspend fun setTextOnMainThread(input: String){
withContext(Main){
textView.text = input
}
}