runBlocking on Android

Coroutines Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Predict the output

This runs on the Android main thread. What happens?

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val name = runBlocking {
        withContext(Dispatchers.Main) { "ready" }
    }
    title = name
}
Options
Hint 1 of 2

Which thread does runBlocking block?

Hint 2 of 2

Where does withContext(Main) need to run?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A It deadlocks: the main thread waits for work that needs the main thread

Correct. withContext(Main) has to post to the main thread, which is blocked inside runBlocking.

Why not the others?
  • B It sets the title to ready right away. The main thread is blocked, so the posted block never runs.
  • C It crashes with NetworkOnMainThreadException. There's no network call here.
  • D It sets the title after one frame. The frame never comes because the main thread is stuck.
Six frames: normal, then runBlocking on the main thread blocks rendering until the ANR deadline at 5 seconds.

Illustrative, based on Compose and Android rules; not a device recording

Text version
Normal
FrameWork (ms)Result
F16on time
F28on time
F37on time
F49on time
F56on time
F68on time

0 dropped frames at 60 Hz (16.7 ms budget); ANR dialog at 5 s: no.

runBlocking on main
FrameWork (ms)Result
F18on time
F25000⏱ late (the next 299 dropped)
F3–✕ dropped (F2 still running)
F4–✕ dropped (F2 still running)
F5–✕ dropped (F2 still running)
F6–✕ dropped (F2 still running)
F7–F301–✕ dropped ×295 (F2 still running)

299 dropped frames at 60 Hz (16.7 ms budget); main thread blocked for 5 s; ANR dialog at 5 s: yes.

30-second answer

runBlocking starts a coroutine and blocks the current thread until it finishes. It bridges blocking code to coroutines in main functions and some legacy callbacks. On the Android main thread it freezes the UI for as long as the work takes, and a suspend call that needs the main thread to resume can deadlock it.

Practise saying it · 35 s. No recording, just a timer

Explain when runBlocking is OK and when it's dangerous.

Say your answer out loud, then check which of these points you covered:

  • Blocks the current thread
  • OK in main functions and background bridges
  • Freezes UI on main and can deadlock
  • Use runTest in tests

Deep dive

In tests use runTest, which skips delays and reports leaked coroutines.

A blocking callback API (an OkHttp Interceptor, a ContentProvider) may need it, but only on a background thread.

If the block calls withContext(Dispatchers.Main) while the main thread is blocked, it waits forever.

Over 5 seconds of a blocked main thread while the user is interacting triggers an ANR.

Common mistakes

  • Calling runBlocking in an Activity to 'wait for the data'.
  • Using runBlocking in tests instead of runTest.
  • Nesting runBlocking inside coroutines.

Senior take & follow-ups

Say what it blocks, and give the deadlock case. That shows you understand dispatchers, not just the rule.

Follow-up questions

Think of your answer first, then open the hint.

  1. Where is runBlocking legitimately used on Android?

    Show hint

    On background threads that must return a value synchronously, such as an OkHttp authenticator.

  2. What does runTest add?

    Show hint

    Virtual time, so delay(10_000) takes no real time.

Suggest a fix if something here is wrong or out of date.