0Pricing
Android Academy · Lesson

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 — lesson 3 of 6. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 6 lessons in the course, and your progress syncs across the web and the CoddyKit app.

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 cleared
  • lifecycleScope — cancelled when Activity/Fragment is destroyed
  • GlobalScope — lives forever (avoid this)
  • runBlocking — for testing only

launch vs async

Two ways to start a coroutine:

  • launch { } — fire-and-forget, no return value
  • async { }.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 operations
  • Dispatchers.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 thread
  • viewModelScope.launch { } — start a coroutine in a ViewModel
  • withContext(Dispatchers.IO) — switch to a background thread
  • async { }.await() — parallel work with a result
  • try/catch works normally inside coroutines

Next: the Repository pattern — clean separation between data sources.

Frequently asked questions

Is the “Coroutines & Suspend Functions” lesson free?

Yes — the full text of “Coroutines & Suspend Functions” is free to read here on the web, and the Android Academy course includes 6 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.

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; this is — lesson 3 of 6, so you can start here or from the beginning and move at your own pace.

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

  1. ViewModel & LiveData
  2. Room Database
  3. Coroutines & Suspend Functions
  4. Repository Pattern
  5. Navigation Component
  6. Dependency Injection with Hilt
← Back to Android Academy