You don't need to call runOnUiThread
as the coroutine will have the main dispatcher as the context.
Let's say you have this helper function to offload work to the I/O thread.
suspend fun <T> withIO(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block)
If you are using a ViewModel, then you can call it like this
viewModelScope.launch {
val result = withIO {
// You are on IO thread here.
update your database
}
// The block will be suspended until the above task is done.
// You are on UI thread now.
// Update your UI.
}
If you are not using a ViewModel, you can also use
withContext(Disptachers.Main) {
val result = withIO {
// You are on IO thread
}
// You are back on the main thread with the result from the task
}