← Back to the library
MobileApplied · 8 min

Android says the app isn't responding

“Users get the "App isn't responding" dialog, mostly on cheaper phones, and Play Console flags our user-perceived ANR rate. Crash reporting shows nothing because nothing crashed.”

ERROR CODES YOU MAY SEE

A code is a clue. Use its meaning and surrounding evidence to narrow the cause.

REASON_ANRAndroid ApplicationExitInfo · platform

The process was killed because it was unresponsive (constant value 6, API 30+).

Read getTraceInputStream() from the record on next launch and upload it; the main thread's stack in that trace shows what it was blocked on.

Official reference for REASON_ANR (opens in new tab)Code definition reviewed

THE PRINCIPLE

Keep the main thread for input and drawing. Anything that can block, including disk, network, locks, IPC and cold initialization, belongs elsewhere, even when it is usually fast.

FIRST MOVES

  1. Read the main thread's stack in the ANR trace (Play Console ANR clusters, ApplicationExitInfo REASON_ANR traces, or /data/anr on a rooted test device). Classify it: I/O, long computation, waiting on a lock, a synchronous binder call, or a deadlock.
  2. Know the triggers: no response to input within 5 s, a BroadcastReceiver over 10 s while the app has a foreground activity, startForegroundService without startForeground within 5 s, slow Service or JobService callbacks.
  3. Turn on StrictMode (detectDiskReads, detectDiskWrites, detectNetwork) in debug builds and fix every violation on startup paths: SharedPreferences commits, database opens, eager SDK initialization in Application.onCreate.
  4. Keep onReceive short: hand longer work to a coroutine with a short budget or to WorkManager, and always call finish() after goAsync().
  5. For React Native, a blocked JS thread doesn't cause ANRs by itself; look for synchronous native module calls, large JSON parsing in native code, and heavy work in native module init.

TOOLS: THEN → NOW

Pulling /data/anr/traces.txt by handPlay Console Android vitals ANR clusters and ApplicationExitInfo traces uploaded on next launch
AsyncTask and ad-hoc threadsKotlin coroutines with Dispatchers.IO and WorkManager for longer jobs
Profiling on a flagship phonePerfetto or Android Studio profiler on a low-end device or emulator

PATTERN SNAPSHOT

// Application.onCreate, debug builds only: make main-thread I/O loud.
if (BuildConfig.DEBUG) {
  StrictMode.setThreadPolicy(
    StrictMode.ThreadPolicy.Builder()
      .detectDiskReads()
      .detectDiskWrites()
      .detectNetwork()
      .penaltyLog()
      .build()
  )
}

CLOSE THE AI. EXPLAIN THIS.

Play's core vital counts only one ANR type. Which one, and what are the overall and per-device bad behavior thresholds?

HOW IT WORKS UNDERNEATH

SOURCES

Guide reviewed