Skip to content

Beginner: Kotlin · Coroutines and Flow · topic 14 of 50 · 30 min

Why coroutines? suspend functions

Explanation

An Android app draws its screen and handles taps on one main thread. If slow work like a network call runs there, the app freezes, and after about 5 seconds Android may show an "App Not Responding" dialog. Coroutines let you write slow work in simple top-to-bottom code that pauses (suspends) without blocking the thread. A suspend function is a function that can pause.

The main thread problem

A thread is a path of execution: a worker that runs your code step by step. Every Android app has a main thread (also called the UI thread). It draws the screen about 60 or more times a second and responds to taps and swipes. If you make it wait for a slow job, such as downloading data, reading a large file or querying a database, it cannot draw or respond. The app freezes. If an input event is not handled for about 5 seconds, Android shows the "Application Not Responding" (ANR) dialog, and users uninstall apps that do this.

Old solutions and their problems

  • Start a new thread for each job: threads are heavy (each uses memory) and passing the result back to the main thread is fiddly.
  • Callbacks: "call this function when the download finishes". Several steps in a row become nested callbacks inside callbacks, which is hard to read and to handle errors in.

Coroutines

A coroutine is a lightweight piece of work that can pause and resume. When a coroutine waits for something slow, it suspends: it steps aside and frees the thread to do other work. When the result arrives, it resumes where it left off, possibly on another thread. You can run thousands of coroutines on a few threads. The best part: the code still reads top to bottom, like normal code.

kotlin
import kotlinx.coroutines.*

suspend fun fetchBalance(): Int {
    delay(1000)          // pretend network call: suspends for 1 second, does not block
    return 2500
}

fun main() = runBlocking {
    println("Loading...")
    val balance = fetchBalance()     // pauses here without freezing the thread
    println("Balance: Rs $balance")
}
runBlocking is only for main functions and tests; in Android you will use viewModelScope (topic 2).

suspend functions

The suspend keyword marks a function that may pause. A suspend function can only be called from another suspend function or from inside a coroutine. That rule lets the compiler make sure pausing is always possible where it happens. Libraries you will use, like Retrofit and Room, offer suspend functions for network and database calls.

delay versus Thread.sleep

delay(1000)Thread.sleep(1000)
What waitsOnly this coroutineThe whole thread
Other work on the threadKeeps runningStops
Where allowedInside coroutines / suspend functionsAnywhere (but blocks)
Think of it like this: Blocking is like a bank clerk who stops serving everyone while waiting on hold with head office. Suspending is like the clerk giving you a token, serving the next customers, and calling you back when head office replies. Same clerk (thread), many customers (coroutines), nobody frozen.

Setting up

kotlin
// app/build.gradle.kts
dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:<version>")
}
Android projects created with recent templates usually already include coroutines through lifecycle libraries. Check the docs for the current version.

Common mistakes

  • Calling a suspend function from a normal function: "Suspend function should be called only from a coroutine or another suspend function".
  • Using Thread.sleep inside a coroutine. Use delay.
  • Thinking suspend makes code run on a background thread by itself. It only allows pausing; you still choose the thread with dispatchers (topic 3).
  • Doing network calls directly on the main thread without coroutines: Android throws NetworkOnMainThreadException.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Why coroutines? suspend functions · 1/6

Main thread = UI thread

Android draws the screen and handles taps on one main thread. Block it, and the app freezes.

Prefer a video by a teacher? Find free videos on “kotlin coroutines suspend functions explained android main thread” on YouTube ↗

In real life: Loading a train's live status

A railway enquiry app shows a train's live running status, which comes from a server and may take two seconds. With a coroutine, the screen shows a spinner, the coroutine suspends while the request is in flight, and the main thread keeps the spinner animating and the back button working. When the response arrives, the coroutine resumes and the status appears. No freezing, no ANR.

kotlin
import kotlinx.coroutines.*

suspend fun liveStatus(train: Int): String {
    delay(2000)                      // network wait
    return "Train $train is running 10 min late"
}

fun main() = runBlocking {
    println("Showing spinner")
    println(liveStatus(12951))
    println("Hiding spinner")
}
The same pattern inside an Android ViewModel uses viewModelScope.launch.

Practice (0/3 done)

Task 1 · Question

What is the main danger of running a 4-second network call on the main thread?

Task 2 · Question

Why does this not compile? suspend fun load(): String { delay(100); return "ok" } fun show() { println(load()) }

Task 3 · Practice

In a Kotlin project (IntelliJ or Android Studio) with kotlinx-coroutines, write suspend fun fetchPrice(item: String): Int that delays 500 ms and returns a price. In main = runBlocking, fetch three prices one after another, measure the total time with measureTimeMillis, and print it. Then replace delay with Thread.sleep and explain what changes for other coroutines.

Quick quiz

Question 1

1.What is a coroutine?

Question 2

2.What does suspend mean on a function?

Question 3

3.Which is the correct way to wait inside a coroutine?

Question 4

4.Where should runBlocking be used?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is a coroutine?

Answer: A lightweight piece of work that can suspend and resume

Many coroutines can share a few threads.

What does suspend mean on a function?

Answer: It may pause without blocking the thread

suspend allows pausing; the dispatcher decides the thread.

Which is the correct way to wait inside a coroutine?

Answer: delay(1000)

delay suspends only the coroutine.

Where should runBlocking be used?

Answer: Only in main functions and tests, not in Android UI code

It blocks the current thread until done.

What does "main-safe" mean for a suspend function?Related

Answer: It is safe to call from the main thread because it moves blocking work elsewhere itself

Callers do not need to switch threads.

From Dispatchers and withContext

What is the polite way to ask a thread to stop?Related

Answer: interrupt(), and the thread checks its interrupted flag

Thread.stop is deprecated and unsafe.

From Threads: doing things at the same time

Why avoid GlobalScope in apps?Related

Answer: Its coroutines are not tied to a screen and can leak

Structured scopes cancel work automatically.

From launch, async and structured concurrency

What does an async function return?Related

Answer: A Future

async functions return Futures.

From Futures and async/await

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Coroutines and Flow” before its exam: launch, async and structured concurrency, Dispatchers and withContext, Flow and StateFlow.
  2. Module 4 exam: Coroutines and Flow · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Android Studio and your first app. 50 topics left in the course before the final exam.

← Previous: Collection operations