ANRs: causes and fixes

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

Pick the fix

Play Console shows ANRs whose main thread is waiting on synchronized(cache) while a worker thread holds it during a network call. Best fix?

Options
Hint 1 of 1

Why is the main thread waiting?

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

Show answer

Answer: A Don't hold the lock during I/O: fetch first, then lock only to update the cache

Correct. Keep critical sections tiny and never do I/O inside them.

Why not the others?
  • B Increase the ANR timeout. Apps can't change it.
  • C Move the main-thread read to onResume. Still blocks on the lock.
  • D Catch the ANR. It isn't an exception you can catch.
Two zoom levels. Frames: normal work, then disk I/O on the main thread. Seconds: the main thread blocked for 5 seconds after a tap triggers an input ANR.

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

Text version
Normal
FrameWork (ms)Result
F18on time
F27on time
F39on time
F48on time
F56on time
F67on time

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

Disk read on main
FrameWork (ms)Result
F18on time
F2120⏱ late (the next 7 dropped)
F3–✕ dropped (F2 still running)
F4–✕ dropped (F2 still running)
F5–✕ dropped (F2 still running)
F6–✕ dropped (F2 still running)
F7–F9–✕ dropped ×3 (F2 still running)

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

Blocked 5 s after a tap
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

An ANR (Application Not Responding) is reported when the main thread can't respond in time: 5 seconds for an input event, 10 seconds for a foreground broadcast's onReceive (60 in the background), and limits for services that start too slowly. Common causes are disk or network on main, lock contention, runBlocking and slow onReceive work. Android vitals in Play Console groups them with main-thread stack traces.

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

Explain ANRs.

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

  • Main thread unresponsive
  • 5 s for input
  • Common causes: I/O on main, locks, runBlocking
  • Read the main thread stack
  • Android vitals

Deep dive

The main thread stack in the ANR trace shows what it was doing; look for locks held by other threads too.

StrictMode catches disk and network access on main during development.

Binder calls to system services can block; avoid them in tight UI paths.

Play's bad-behaviour threshold for user-perceived ANR rate is 0.47%.

Common mistakes

  • Blaming the device when the trace shows your lock.
  • Fixing only the top frame of the stack.
  • Doing SharedPreferences commit() on main.

Senior take & follow-ups

Name the timeouts and a real investigation: read the main thread stack, then who holds the lock.

Follow-up questions

Think of your answer first, then open the hint.

  1. Where do you find production ANRs?

    Show hint

    Android vitals in Play Console, and ApplicationExitInfo on device.

  2. Why can a background thread cause an ANR?

    Show hint

    It holds a lock the main thread is waiting for.

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