Sparround

Main thread, ANR, processes & threads

Each app runs in one process by default, with UI on a single main (UI) thread. Two iron rules:

  • Never block the main thread — the UI freezes.
  • Touch UI only from the main thread — otherwise an exception.

ANR (Application Not Responding) — the system dialog, triggered by:

  • An input event not handled within 5 seconds
  • A BroadcastReceiver not finishing in ~10 seconds
  • A foreground service not calling startForeground in time

Typical culprits: network/disk on the main thread, synchronous IPC, heavy JSON parsing, SharedPreferences commit(), lock contention.

The modern fix: coroutines + dispatchers (offload to IO/Default, present on Main). Legacy tools (AsyncTask — deprecated, HandlerThread, ExecutorService) may come up — know why AsyncTask died: lifecycle-unaware, leak-prone, weak error handling.

kotlin
// PİS: main thread-də disk + şəbəkə
override fun onCreate(savedInstanceState: Bundle?) {
    val cached = File(filesDir, "rates.json").readText()      // disk!
    val rates = fetchRatesSync()                                // şəbəkə!!
}

// YAXŞI: iş IO-da, nəticə Main-də
lifecycleScope.launch {
    val rates = withContext(Dispatchers.IO) {
        val cached = File(filesDir, "rates.json").readText()
        parseOrFetch(cached)
    }
    binding.ratesView.render(rates)   // main thread
}

ANR-prone code and its fix

Be ready for the diagnostic question: "ANRs spiked in production — what do you do?" The flow: Play Console ANR rate and stack traces → what the main thread is waiting on → local reproduction with StrictMode → the fix (move work off the main thread) → watch the metric drop post-release. Knowing that exceeding the Android vitals ANR threshold also hurts Play Store visibility signals real experience.

🛠 Practice task

See an ANR yourself: put Thread.sleep(8000) in onCreate and tap the app — wait for the system dialog.

  • Then enable StrictMode in your Application (penaltyLog) and read a file on the main thread — find the violation in logcat.
  • Move that work into withContext(Dispatchers.IO) and confirm the violation disappears.

Done when: you can list your diagnostic steps for "ANRs spiked in production".

📚 Sources and documentation