ANR Errors in Android Apps: Causes and Fixes (2026 Guide)
ANR — Application Not Responding — is Android's way of telling you the main thread is blocked. It is one of the top reasons users uninstall apps and one of the easiest categories of bug to diagnose if
ANR — Application Not Responding — is Android's way of telling you the main thread is blocked. It is one of the top reasons users uninstall apps and one of the easiest categories of bug to diagnose if you know what to look for. This guide covers causes, detection, and fixes with real code.
What an ANR actually is
The system watches your main thread (UI thread). If the thread does not process an input event within 5 seconds, or a broadcast receiver does not complete within 10 seconds, or a foreground service does not start within 5 seconds, the system shows the "App isn't responding" dialog. From the user's perspective, the app is frozen.
Every ANR triggers a dump in /data/anr/traces.txt on the device. Play Console vitals aggregates them. Your app's ANR rate is a first-class metric.
Common causes
1. Network calls on the main thread
The classic mistake. A synchronous HTTP call takes whatever the network is willing to give — sometimes 30 seconds. StrictMode catches this in development but only if you remember to enable it.
Fix: all I/O goes on a background thread. Kotlin coroutines, RxJava, or plain Executors. If you are writing new code in 2026, use suspend functions with Dispatchers.IO.
2. Disk I/O on the main thread
Reading a JSON config from disk, decoding a bitmap, initializing Room — all of these block the main thread. Small files are fast most of the time and then an old phone with fragmented flash turns 50ms into 3 seconds.
Fix: move to background. For configs, consider DataStore (coroutines-native). For images, Glide / Coil handle background decode automatically.
3. Lock contention
Your main thread waits for a lock held by a background thread that is blocked on a database write. Classic deadlock-adjacent ANR.
Fix: avoid locking on main. If you must synchronize access to a shared resource, do the heavy work on the background thread and post the result back via Handler.post() or a coroutine withContext(Dispatchers.Main).
4. Slow broadcast receivers
Your onReceive() does anything heavy. The 10-second budget runs out.
Fix: start a JobIntentService or enqueue work via WorkManager from the receiver. Return from onReceive() in under a second.
5. RecyclerView with expensive bind
onBindViewHolder decodes a bitmap or parses JSON. Scrolling stutters, eventually ANR.
Fix: keep onBindViewHolder trivial. Pre-compute everything in the ViewModel. Use DiffUtil for updates. Image loading through Glide / Coil.
6. Content provider queries
A ContentResolver.query() on the main thread. Often hidden inside a library you added last week.
Fix: wrap provider queries in coroutines. For contact lists and media store, use the paginated APIs introduced in Android 11.
7. ANR on startup
SplashActivity initializes five SDKs synchronously. Firebase, Crashlytics, Segment, Amplitude, Mixpanel. Each takes 200ms. User sees a frozen splash for a second, then ANR.
Fix: App Startup library. Lazy init anything not critical to first paint. Benchmark your cold start budget: first frame should be under 500ms.
Detection
Development
- Enable StrictMode in
Application.onCreate():
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
This logs every main-thread I/O. Grep for StrictMode in logcat.
- Profile with Android Studio CPU profiler. Look for anything over 100ms on the main thread.
- Run your app with
adb shell am monitorand triggeradb shell input keyevent KEYCODE_BACKafter a slow action. Watch for ANR dialogs.
Production
- Play Console vitals — ANR rate per version, user-perceived vs background
- Firebase Crashlytics (custom keys + non-fatal reports when you detect your own slowness)
- Logcat on device —
adb shell dumpsys activity | grep -A 5 "ANR"after reproducing /data/anr/traces.txt— the stack trace at the moment of ANR
Fixes by pattern
Rule 1: nothing blocking on main
Ever. If you are unsure, move it to background.
Rule 2: budget your startup
Every SDK init, every cache warm-up, every remote config fetch. Everything runs against a budget measured in milliseconds. Cold start should land on first frame within 500ms on a mid-tier 2023 device.
Rule 3: tight loops over collections → always IO dispatcher
Sorting a 1000-item list is fast. Sorting a 100-thousand-item list is not. Move to background.
Rule 4: database migrations at launch
Room migrations run synchronously by default. A 500k-row migration on upgrade locks the main thread and triggers ANR on every launch for affected users.
Fix: run migrations asynchronously behind a loading screen, or defer non-critical migrations to background work.
How SUSA catches ANRs
SUSA monitors logcat continuously during exploration. ANR detection fires on:
ANR inlog lineInput event dispatching timed outReason: Broadcast of Intentwithnot responding
Each ANR gets a full issue report: which screen, which action triggered it, full logcat context, screenshot at time of ANR. The impatient persona abandons after 2 seconds — revealing slow screens that do not quite ANR but still feel broken. The stress test suite fires rapid taps and rotations to trigger ANRs that only appear under pressure.
susatest-agent test myapp.apk --persona impatient --steps 100
JyotishyaMitra in a recent exploration had 24 ANRs across 50 steps — mostly on the astrology calculation screens where PHP-style math was running on the UI thread. Moving that math to Dispatchers.Default dropped ANR rate from 48% to 2%.
Debugging checklist
- Reproduce on a physical device, not an emulator (timing differs)
- Grab
/data/anr/traces.txtimmediately after - Identify the thread at the top of the trace — usually "main"
- Walk the stack down until you find your code
- The line where your code enters a
lock(),read(),query(), orrunBlocking— that is the culprit - Move it to a background dispatcher
- Re-run SUSA to confirm
ANR is a solvable class of bug. Detection is cheap, fixes are well-understood, and reduction from 10% to under 0.5% is achievable in most codebases within a release cycle.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free