What is an ANR? Understanding and Conquering the Dreaded Android Error

Sandeep Kella
3 min readFeb 18, 2024

--

In the world of Android app development, the acronym “ANR” strikes a note of caution. Short for “Application Not Responding,” ANRs signal a major roadblock in user experience. An ANR occurs when the main thread of your application becomes frozen, preventing the app from responding to user input. Users are then faced with the infamous ANR dialog, offering to either wait or force-close the app.

The Culprit: Blocking the Main Thread

Android’s main thread is responsible for rendering the UI and handling events like touch interactions. Any lengthy process that executes on this thread can trigger an ANR. Typical scenarios include:

  • Network operations: Waiting for responses from slow or unavailable servers.
  • Intensive file I/O: Copying large files or complex database transactions.
  • Complex calculations: CPU-heavy algorithms running within the UI thread.
  • Infinite loops or deadlocks: Code that inadvertently freezes the thread.

Simulating an ANR

Let’s illustrate how to cause an ANR intentionally (don’t try this in production apps!):

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button triggerAnrButton = findViewById(R.id.trigger_anr_button);
triggerAnrButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
Thread.sleep(10000); // Block the main thread for 10 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}

In this example, clicking the button will pause the main thread for 10 seconds, well beyond the usual ANR threshold.

Different Ways ANR Can Occur:

  1. Blocking the UI Thread: Performing time-consuming operations on the UI thread, such as network requests or database queries, can cause ANR.
  2. Deadlocks: When multiple threads are waiting for each other to release resources, a deadlock can occur, leading to ANR.
  3. Broadcast Receivers: Lengthy operations within a broadcast receiver on the main thread can trigger ANR.
  4. Service ANR: ANR can also occur if a service in your application takes too long to respond.

How to Combat ANRs

The key to preventing ANRs lies in offloading long-running tasks:

  • AsyncTasks: A classic Android utility for background operations with progress updates back to the UI thread.
  • Threads: Create separate worker threads for intensive workloads, making sure to synchronize communication with the main thread using handlers or other mechanisms.
  • Coroutines (Kotlin): Kotlin’s coroutines make writing asynchronous code cleaner and less error-prone.
  • Third-party libraries: Specialized libraries like RxJava offer powerful abstractions for asynchronous operations.
  • Strict Mode: Use StrictMode in development to detect accidental main thread blocks, helping you catch potential ANRs early.

Beyond the Basics

Solving ANRs often requires deeper analysis. Tools like the Android profiler and ANR traces (found in the Play Console) offer insights into what’s clogging the main thread. Optimizing data structures, algorithms, and I/O processes might be necessary for smoother performance.

A User-First Philosophy

Ultimately, avoiding ANRs demands prioritizing user experience over convenience. Deferring non-essential tasks, providing progress indicators, and handling unresponsive components gracefully enhance usability while also minimizing the chances of an ANR.

--

--

Sandeep Kella

Android developer @PhonePe, writes about Android development and productivity.