Coroutines are Kotlin’s way of dealing with asynchronous tasks. They can execute tasks sequentially.
Coroutines require a:
- Job – cancellable background task with a lifecycle that culminates in its completion. Jobs can be arranged in a parent-child hierarchy so that cancellation of the parent cancels all child jobs
- Dispatcher – sends off coroutines to run on various threads
- Scope – combines information, including a job and dispatcher, to define the context in which a coroutine runs. Scopes keep track of coroutines
The keyword suspend is Kotlin’s way of marking a function, or function type, available to coroutines. When a coroutine calls a function marked suspend, instead of blocking until that function returns like a normal function call, it suspends execution until the result is ready then it resumes where it left off with the result. While it’s suspended waiting for a result, it unblocks the thread that it’s running on so other functions or coroutines can run. The suspend keyword doesn’t specify the thread code runs on. Suspend functions may run on a background thread or the main thread.
import ...
class MyViewModel(
val database: MyDatabaseDao,
application: Application) : AndroidViewModel(application) {
private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) // Set Dispatcher on the Main thread and the job
private var myObject = MutableLiveData<MyObject?>()
init {
initialiseMyFunction() // When the class is instantiated call initialiseMyFunction
}
private fun initialiseMyFunction() {
uiScope.launch { // This function starts by running on the Main thread as the Viewmodel usually is involved in updating the UI
myObject.value = getObjectFromDatabase() // Then it calls the getObjectFromDatabase function
}
}
private suspend fun getObjectFromDatabase(): MyObject? { // We make this a suspend functino so it won't block the UI Thread from doing work
return withContext(Dispatchers.IO) { // This is run on the background thread as we don't eant it blocking the UI thread and messing up the user experience
var myObject = database.getObject()
myObject // Return the object
}
}
override fun onCleared() {
super.onCleared()
viewModelJob.cancel() // Be sure to cancel the Job (and hence any associated coroutines) when the ViewModel is destroyed, to prevent memory leaks
}
}
See examples in the Sleep Tracker app from the Google Udacity course: Developing Android Apps with Kotlin
