How to Fix Android ANR (Application Not Responding)
In this tutorial, you'll learn about How to Fix Android ANR (Application Not Responding). We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
Your app freezes and shows:
ANR in com.example.app (com.example.app/.MainActivity)
Reason: Input dispatching timed out (Waiting to send key event
because the touched window is not responding)
Or:
Reason: Executing service com.example/.MyService
The app's main thread is blocked for more than 5 seconds (input) or 200 seconds (background service).
Quick Fix
Step 1: Find the culprit with StrictMode
// Enable StrictMode in Application.onCreate
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
)
}
StrictMode logs a stack trace every time the main thread does disk I/O or network access.
Step 2: Move network calls off the main thread
// Wrong - network on main thread
val result = URL("https://api.example.com").readText()
// Right - use coroutine
lifecycleScope.launch(Dispatchers.IO) {
val result = withContext(Dispatchers.IO) {
URL("https://api.example.com").readText()
}
withContext(Dispatchers.Main) {
textView.text = result
}
}
Step 3: Move database operations off the main thread
// Wrong - Room query on main thread
val user = db.userDao().getUserSync(42)
// Right - Room supports suspend functions
viewModelScope.launch {
val user = withContext(Dispatchers.IO) {
db.userDao().getUser(42)
}
}
Room blocks the calling thread if you use synchronous DAO methods without a suspend prefix.
Step 4: Avoid large Bitmap decoding on the main thread
// Wrong
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.large_image)
// Right - use Glide or Coil which handle threading
Glide.with(this).load(R.drawable.large_image).into(imageView)
Step 5: Check for deadlocks
// Wrong - main thread waiting for background thread that waits for main thread
synchronized(lockA) {
runOnUiThread {
synchronized(lockB) { }
}
}
Use Thread dumps to diagnose deadlocks:
adb shell kill -3 <pid>
adb pull /data/anr/traces.txt
Step 6: Reduce work in onCreate and onResume
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Defer heavy work
Handler(Looper.getMainLooper()).post {
performHeavySetup()
}
}
Step 7: Use WorkManager for background tasks
// Instead of a Service on the main thread
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.build()
WorkManager.getInstance(this).enqueue(workRequest)
Prevention
- Never do network, disk, or database operations on the main thread.
- Enable StrictMode in debug builds.
- Use
lifecycleScope,viewModelScope, or coroutines for async work. - Keep
onCreate,onResume, andonBindlightweight.
Common Mistakes with crash anr
- Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
DodaTech Tool Reference
Doda Browser's Performance Profiler captures frame render times and main-thread stalls, helping identify the exact code path causing ANRs before they happen in production.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro