Top Causes of ANRs in Android and How to Eliminate Them (Complete Developer Guide)
Source: Dev.to
Introduction
Imagine a user opens your Android app, taps a button, and nothing happens. The screen freezes. After a few seconds, Android shows Application Not Responding (ANR). Most users don’t wait—they close the app and uninstall it. That’s why ANRs are one of the most dangerous performance issues in Android apps.
According to the Android Developers documentation, ANRs happen when the main thread is blocked and cannot respond to user input within a specific time. If your ANR rate becomes high, Google Play can reduce your app’s visibility. Understanding ANRs is therefore critical.
What is an ANR? (Simple Explanation)
Official Definition
ANR occurs when the UI thread is blocked and cannot process user input or draw frames. Android shows an ANR when:
- Input event not handled within 5 seconds
BroadcastReceiverruns too long- Service takes too long to start
- Job or foreground service delays response
Real‑World Example
Think of your app like a restaurant.
| Role | Analogy |
|---|---|
| UI Thread | Waiter |
| Background Thread | Kitchen |
| User | Customer |
Good Flow
Customer orders → Waiter sends to kitchen → Kitchen prepares → Waiter delivers (smooth).
Bad Flow (ANR)
Customer orders → Waiter goes to kitchen and starts cooking himself → No one takes new orders, no one serves food → Restaurant stops working.
This mirrors heavy work on the UI thread.
Top Causes of ANRs
1. Heavy Work on Main Thread
Running network calls, database queries, file reading, JSON parsing, or image processing on the UI thread blocks it. Android documentation states: Keep the main thread unblocked and move heavy work to worker threads.
2. Long Database or Network Operations
val data = api.getUsers() // running on main threadThis blocks the UI and can cause an ANR.
3. BroadcastReceiver Doing Heavy Work
BroadcastReceiver should perform only quick tasks. Long‑running work inside onReceive leads to ANRs. Android recommends moving such work to background threads.
4. Service Not Starting in Time
A foreground service must call startForeground() within 5 seconds; otherwise, an ANR occurs.
5. Deadlocks and Thread Blocking
When one thread waits for another (e.g., Thread A waiting for Thread B), the app freezes. This deadlock is a major ANR cause.
Common Developer Mistakes
Running API Calls in an Activity
override fun onCreate() {
super.onCreate()
val users = api.getUsers() // Bad: runs on UI thread
}Large JSON Parsing on UI Thread
val json = File("data.json").readText() // Bad: blocks UIBest Practices to Avoid ANRs
Use Coroutines
viewModelScope.launch { val users = repository.getUsers() }Use
Dispatchers.IOfor I/OwithContext(Dispatchers.IO) { api.getUsers() }Use Flow for Continuous Data
repository.getUsersFlow() .flowOn(Dispatchers.IO)Use WorkManager for Background Tasks (e.g., sync, upload, downloads, scheduling)
Keep
BroadcastReceiverLightweightoverride fun onReceive(context: Context, intent: Intent) { CoroutineScope(Dispatchers.IO).launch { repository.sync() } }
Modern Kotlin Code Example
class UserRepository(
private val api: UserApi
) {
suspend fun getUsers(): List = withContext(Dispatchers.IO) {
api.getUsers()
}
}@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users = _users.asStateFlow()
init { loadUsers() }
private fun loadUsers() {
viewModelScope.launch {
_users.value = repository.getUsers()
}
}
}@Composable
fun UserScreen(viewModel: UserViewModel) {
val users by viewModel.users.collectAsState()
LazyColumn {
items(users) { user ->
Text(user.name)
}
}
}Real‑World Use Case
Scenario: The app scans device videos.
- Wrong: Scanning files directly in an
Activity→ UI freezes → ANR. - Correct: Show a splash screen, let the repository use
Dispatchers.IOto scan, emit results via aFlow, and update the UI as data arrives.
Result: No ANR, smooth user experience.
Key Takeaways
- Core Rule: Never block the main thread.
- UI thread must always remain free for user input and rendering.
Conclusion
ANRs are not just performance issues; they directly impact user experience, app rating, Play Store ranking, and revenue. The safest strategy is simple: keep the UI thread clean and move all heavy work to background threads. By following Android’s official guidelines and modern Kotlin practices, ANRs can be almost eliminated.