DEV Community

AhsanAhmed03
AhsanAhmed03

Posted on

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

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 Android Developers documentation, ANRs happen when the main thread is blocked and cannot respond to user input within a specific time.

And if your ANR rate becomes high, Google Play can reduce your app visibility.

So understanding ANRs is not optional — it’s 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 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.

  • UI Thread = Waiter
  • Background Thread = Kitchen
  • User = Customer

Good Flow

Customer orders → Waiter sends to kitchen → Kitchen prepares → Waiter delivers

Everything runs smoothly.

Bad Flow (ANR)

Customer orders → Waiter goes to kitchen and starts cooking himself

Now:

  • No one takes new orders
  • No one serves food
  • Restaurant stops working

This is exactly what happens when UI thread does heavy work.

Top Causes of ANRs

1. Heavy Work on Main Thread ❌

Problem

Running:

  • Network calls
  • Database queries
  • File reading
  • JSON parsing
  • Image processing

on UI thread.

Android documentation clearly states:

Keep main thread unblocked and move heavy work to worker threads

2. Long Database or Network Operations ❌

Example:

val data = api.getUsers() // running on main thread
Enter fullscreen mode Exit fullscreen mode

This blocks UI.

Result → ANR.

3. BroadcastReceiver Doing Heavy Work ❌

BroadcastReceiver should do small quick tasks only.

If it runs too long → ANR.

Android recommends moving work to background threads.

4. Service Not Starting in Time ❌

Foreground service must call:

startForeground()
Enter fullscreen mode Exit fullscreen mode

within 5 seconds.

Otherwise → ANR.

5. Deadlocks and Thread Blocking ❌

Example:

Thread A waiting for Thread B
Thread B waiting for Thread A

Result:

App freezes.

Android documentation calls this deadlock, a major ANR cause.

**Common Developer Mistakes

❌ Running API calls in Activity**

override fun onCreate() {
    super.onCreate()

    val users = api.getUsers()
}
Enter fullscreen mode Exit fullscreen mode

Wrong approach.

❌ Large JSON parsing on UI thread

val json = File("data.json").readText()
Enter fullscreen mode Exit fullscreen mode

ANR risk.

Best Practices to Avoid ANRs

✅ Use Coroutines

viewModelScope.launch {
    val users = repository.getUsers()
}
Enter fullscreen mode Exit fullscreen mode

Moves work off main thread.

✅ Use Dispatchers.IO

withContext(Dispatchers.IO) {
    api.getUsers()
}
Enter fullscreen mode Exit fullscreen mode

Optimized for I/O.

✅ Use Flow for Continuous Data

repository.getUsersFlow()
    .flowOn(Dispatchers.IO)
Enter fullscreen mode Exit fullscreen mode

Efficient and non-blocking.

✅ Use WorkManager for Background Tasks

Good for:

  • Sync
  • Upload
  • Downloads
  • Scheduling

✅ Keep BroadcastReceiver Lightweight

override fun onReceive(context: Context, intent: Intent) {

    CoroutineScope(Dispatchers.IO).launch {
        repository.sync()
    }
}
Enter fullscreen mode Exit fullscreen mode

Modern Kotlin Code Example
Repository

class UserRepository(
    private val api: UserApi
) {

    suspend fun getUsers(): List<User> {
        return withContext(Dispatchers.IO) {
            api.getUsers()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

ViewModel

@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()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Jetpack Compose UI

@Composable
fun UserScreen(viewModel: UserViewModel) {

    val users by viewModel.users.collectAsState()

    LazyColumn {
        items(users) { user ->
            Text(user.name)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case
Video Fetching App

Scenario:

App scans device videos.

Wrong

Scanning files in Activity.

UI freezes.

ANR occurs.

Correct

  • Splash loads videos
  • Repository uses Dispatchers.IO
  • Flow emits data
  • UI updates smoothly

Result:

✔ No ANR
✔ Smooth scrolling
✔ Fast loading
✔ Better Play Store rating

**Key Takeaways

Core Rule**

Never block the main thread

Important Points

✔ UI thread must always be free
✔ Move heavy work to background threads
✔ Use Coroutines and Flow
✔ Keep BroadcastReceiver lightweight
✔ Use WorkManager for long tasks
✔ Avoid deadlocks and thread blocking
✔ Monitor ANR in Play Console

Conclusion

ANRs are not just performance issues.

They directly impact:

  • User experience
  • App rating
  • Play Store ranking
  • Revenue

The safest strategy is simple:

Keep the UI thread clean and move all heavy work to background threads.

If you follow Android’s official guidelines and modern Kotlin practices, ANRs can be almost eliminated.

Feel free to reach out to me with any questions or opportunities at (aahsanaahmed26@gmail.com)
LinkedIn (https://www.linkedin.com/in/ahsan-ahmed-39544b246/)
Facebook (https://www.facebook.com/profile.php?id=100083917520174).
YouTube (https://www.youtube.com/@mobileappdevelopment4343)
Instagram (https://www.instagram.com/ahsanahmed_03/)

Top comments (0)