Coroutines & Suspend Functions
Write asynchronous code that reads like synchronous code. Use suspend functions, coroutine scopes, and dispatchers (IO, Main, Default).
Coroutines & Suspend Functions is a free Android Academy lesson on CoddyKit. This is lesson 3 of 6. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, and your progress syncs across the web and the CoddyKit app. The Android Academy course includes 6 lessons in total.
The Problem: Blocking the UI Thread
Android runs all UI work on the main thread. If you do a network request or database read on the main thread, the UI freezes until it finishes.
If the UI freezes for more than 5 seconds, Android shows an ANR (App Not Responding) dialog and the user can force-close your app.
What Are Coroutines?
Kotlin Coroutines are a way to write asynchronous code that looks sequential — no callbacks, no RxJava chains.
- Lightweight — thousands of coroutines can run concurrently
- Suspendable — a coroutine can pause and resume without blocking a thread
- Structured — they respect a lifecycle (scope)
suspend Functions
A function marked suspend can pause its execution without blocking the thread. It can only be called from another suspend function or a coroutine scope.
import kotlinx.coroutines.*
suspend fun fetchData(): String {
delay(1000) // simulates 1 second network call
return "Data loaded!"
}
fun main() = runBlocking {
println("Fetching...")
val result = fetchData() // suspends here, doesn't block
println(result) // Data loaded!
println("Done")
}Coroutine Scopes
Every coroutine runs inside a scope that defines its lifecycle:
viewModelScope— cancelled when ViewModel is clearedlifecycleScope— cancelled when Activity/Fragment is destroyedGlobalScope— lives forever (avoid this)runBlocking— for testing only
launch vs async
Two ways to start a coroutine:
launch { }— fire-and-forget, no return valueasync { }.await()— returns a result you can wait for
import kotlinx.coroutines.*
fun main() = runBlocking {
// launch: no return value
launch {
delay(500)
println("launch done")
}
// async: returns a Deferred<T>
val deferred = async {
delay(300)
42
}
val result = deferred.await()
println("async result: $result")
}Dispatchers: Which Thread?
Dispatchers control which thread(s) the coroutine runs on:
Dispatchers.Main— UI thread (for updating views)Dispatchers.IO— for network and disk operationsDispatchers.Default— for CPU-intensive work
Use withContext(Dispatchers.IO) { } to switch dispatcher inside a coroutine.
viewModelScope Example
Fetch data in a ViewModel without blocking the UI:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
class DataViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// Switch to IO thread for network
val data = withContext(Dispatchers.IO) {
// simulate network request
delay(1000)
"Result from server"
}
// Back on Main thread — safe to update UI
_uiState.value = data
}
}
}Error Handling in Coroutines
Handle exceptions inside a coroutine with try/catch, just like regular code:
viewModelScope.launch {
try {
val result = withContext(Dispatchers.IO) {
api.fetchUser() // may throw IOException
}
_user.value = result
} catch (e: Exception) {
_error.value = "Failed: ${e.message}"
}
}Parallel Coroutines
Run two tasks in parallel and wait for both to finish using async/await:
viewModelScope.launch {
// Both run at the same time!
val userDeferred = async(Dispatchers.IO) { api.getUser() }
val postsDeferred = async(Dispatchers.IO) { api.getPosts() }
val user = userDeferred.await()
val posts = postsDeferred.await()
_state.value = UiState(user, posts)
}Quick Check
Which coroutine dispatcher should you use for network and database operations?
Recap: Coroutines
You can now write async code without callbacks:
suspend fun— can pause without blocking the threadviewModelScope.launch { }— start a coroutine in a ViewModelwithContext(Dispatchers.IO)— switch to a background threadasync { }.await()— parallel work with a result- try/catch works normally inside coroutines
Next: the Repository pattern — clean separation between data sources.
Learn Kotlin with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 36
- Lessons
- 152
Frequently Asked Questions
Is the “Coroutines & Suspend Functions” lesson free?
Yes — any 3 lessons of the Android Academy learning path, including “Coroutines & Suspend Functions”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Android Academy course includes 6 lessons in total.
What will I learn in “Coroutines & Suspend Functions”?
Write asynchronous code that reads like synchronous code. Use suspend functions, coroutine scopes, and dispatchers (IO, Main, Default). You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Android Academy?
No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 6.
How long does the “Coroutines & Suspend Functions” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Android Academy lesson?
Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- ViewModel & LiveData
- Room Database
- Coroutines & Suspend Functions
- Repository Pattern
- Navigation Component
- Dependency Injection with Hilt