ANR, short for Application Not Responding, is the condition in which Android detects that an app’s main thread has been blocked for too long to respond to user input or to complete a system callback. In mobile performance, an ANR is treated as a failure comparable to a crash: the user sees a frozen screen and, in the foreground case, a dialog offering to close the app or wait.
ANRs matter beyond the single frozen session. Android vitals in Google Play tracks the user-perceived ANR rate, and apps above the bad behavior threshold can receive reduced visibility in the store.
How Android detects an ANR
Every Android app has one main thread, also called the UI thread, which processes input events, draws frames and runs component lifecycle callbacks. The system sets a timeout whenever it hands the app a piece of work; if the app does not finish that work before the timeout expires, the system declares an ANR.
The timeouts differ by type of work. The table lists the commonly documented values; exact values can vary between Android versions and device configurations.
| Trigger | Timeout | What must finish |
|---|---|---|
| Input dispatch | 5 seconds | Response to a touch or key event |
| Foreground broadcast receiver | About 10 seconds | onReceive in a foreground broadcast |
| Background broadcast receiver | About 60 seconds | onReceive in a background broadcast |
| Foreground service start | About 20 seconds | Service lifecycle callbacks |
| startForeground call | About 10 seconds | Promotion of a foreground service |
| Job execution | Platform-defined limits | Responding to job start or stop calls |
When an ANR occurs, the system captures thread stack traces of the app’s process. These traces show what the main thread was doing at the moment of the timeout and are the starting point for every investigation.
Common causes of ANRs
Nearly every ANR comes down to work that does not belong on the main thread, or a main thread that waits for something it cannot get. The patterns below account for most cases in production.
| Cause | Typical stack trace signature | Fix |
|---|---|---|
| Disk I/O on main thread | File, database or SharedPreferences calls | Move I/O to a background dispatcher |
| Network on main thread | Socket or HTTP client frames | Use asynchronous networking |
| Lock contention | Main thread waiting on a monitor | Shorten locks, avoid sharing with slow work |
| Deadlock | Two threads waiting on each other | Enforce lock ordering |
| Slow app startup | Heavy work in Application.onCreate | Defer and lazily initialize |
| Binder call to busy system service | Blocking IPC frames | Call off the main thread or cache results |
A frequent hidden cause is synchronous SharedPreferences commits and database queries during lifecycle callbacks. They are fast on a new device with free storage but can take hundreds of milliseconds on an older phone with slow, nearly full flash memory.
ANR compared with related performance problems
An ANR is the extreme end of a spectrum of main-thread problems. Distinguishing it from neighboring issues helps teams pick the right tools and metrics.
| Issue | Duration of blocking | User experience |
|---|---|---|
| Jank | Longer than one frame, about 16 ms at 60 Hz | Stuttering scroll or animation |
| Frozen frame | Longer than about 700 ms | Screen visibly stops |
| ANR | Seconds, beyond the timeout | Dialog or forced close |
| Crash | Not a blocking problem | App terminates with an exception |
| Slow app startup | Long time to first frame | Blank or splash screen lingers |
Crash analytics tools often collect ANRs together with crashes, but ANRs need different analysis: there is no exception, only a snapshot of blocked threads. Because the snapshot is taken at the timeout, the visible frame may be a victim, not the original culprit that started the delay.
Measuring and preventing ANRs
Production data comes mainly from Android vitals in the Play Console and from crash reporting SDKs. Android vitals reports the user-perceived ANR rate, the share of daily active users who experienced at least one ANR that they could notice. Google Play has used a bad behavior threshold of 0.47% overall and 8% on any single device model; teams should check the current values in the console.
Prevention combines development discipline with tooling:
- StrictMode in debug builds flags disk and network access on the main thread.
- Coroutines or executors move I/O and computation to background threads by default.
- ApplicationExitInfo reports past ANRs with traces on Android 11 and later.
- System tracing with Perfetto shows exactly where main-thread time goes.
- Testing on low-end devices exposes delays that flagship phones hide.
A good working rule is to keep each main-thread task well below one frame and to treat any main-thread call that touches storage, network or another process as suspect.
Common mistakes when fixing ANRs
ANR fixes often fail because they treat the symptom. Increasing a timeout is not possible for most triggers and would only hide the problem. Wrapping slow code in a thread while the main thread still waits synchronously for its result produces exactly the same ANR.
Another mistake is to analyze only the top frame of one trace. Grouping many ANR reports by the full main-thread stack and checking what other threads held at the same time usually reveals the real lock or I/O bottleneck.
A plain-language summary
An ANR happens when an Android app freezes for several seconds and stops reacting to taps. The phone then shows a message saying the app is not responding and asks whether to close it or keep waiting.
Think of a shop with a single cashier. If the cashier leaves the counter to search the storeroom, the queue stops moving. After a while, customers give up. Good apps keep the cashier at the counter and send someone else to the storeroom.
An example from practice
A shopping app sees its user-perceived ANR rate climb to about 0.9% after a release, well above the store’s bad behavior threshold. Most reports come from budget phones with limited storage.
The grouped traces show the main thread waiting on a lock while a background thread rewrites a large preferences file. The new release had added a recently viewed products list to SharedPreferences and saved it synchronously on every screen change. The team moves the list to a database accessed from a background dispatcher and switches remaining preference writes to asynchronous apply calls.
Two weeks after the fix, the ANR rate falls to about 0.2%, and the app returns below the threshold. Store listing visibility recovers, and the team adds StrictMode checks to its debug builds to catch similar regressions before release.