Top Causes of ANRs in Android and How to Eliminate Them (Complete Developer Guide)

Published: (April 6, 2026 at 02:33 PM EDT)
4 min read
Source: Dev.to

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
  • BroadcastReceiver runs too long
  • Service takes too long to start
  • Job or foreground service delays response

Real‑World Example

Think of your app like a restaurant.

RoleAnalogy
UI ThreadWaiter
Background ThreadKitchen
UserCustomer

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 thread

This 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 UI

Best Practices to Avoid ANRs

  • Use Coroutines

    viewModelScope.launch {
        val users = repository.getUsers()
    }
  • Use Dispatchers.IO for I/O

    withContext(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 BroadcastReceiver Lightweight

    override 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.IO to scan, emit results via a Flow, 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.

0 views
Back to Blog

Related posts

Read more »