Keep your app responsive

Figure 1. An ANR dialog displayed to the user.

This page describes how the Android system determines whether an app isn't responding and shows how to keep your app responsive.

No matter how well-written your code is, it's possible for your app to still feel sluggish, hang, freeze for significant periods, or take too long to process input. If your app isn't responsive, you can get an Application Not Responding (ANR) dialog.

The Android system guards against apps that are insufficiently responsive for a period of time by displaying an ANR dialog that says your app stopped responding, as shown in figure 1. When this happens, the system offers the user an option to quit the app. It's critical to design responsiveness into your app so the system never displays an ANR dialog to the user.

ANR triggers

Generally, the system displays an ANR if an app can't respond to user input, such as when an app blocks an I/O operation—typically a network access—on the UI thread, preventing the system from processing incoming user input events. Another example is when an app spends too much time building an elaborate in-memory structure or computing the next move in a game on the UI thread. It's important to ensure these computations are efficient, as even efficient code takes time to run.

In any situation that your app performs a potentially lengthy operation, don't perform the work on the UI thread. Instead, create a worker thread and do most of the work there. This keeps the UI thread—which drives the user interface event loop—running and prevents the system from concluding that your code is frozen. Because such threading usually is accomplished at the class level, you can think of responsiveness as a class problem. Compare this with basic code performance, which is a method-level concern.

In Android, app responsiveness is monitored by the ActivityManager and WindowManager system services. Android displays the ANR dialog for an app when it detects one of the following conditions:

  • No response to an input event—such as key press or screen tap events—within 5 seconds.
  • A BroadcastReceiver doesn't finish executing within 10 seconds.

Avoid ANRs

Android apps normally run entirely on a single thread by default: the UI thread (or main thread). This means anything your app is doing in the UI thread that takes a long time to complete can trigger the ANR dialog because your app isn't giving itself a chance to handle the input event or intent broadcasts.

Therefore, any method that runs in the UI thread must do as little work as possible on that thread. In particular, activities must do as little as possible to set up in key life-cycle methods, such as onCreate() and onResume(). Potentially lengthy operations such as network or database operations, or computationally expensive calculations such as resizing bitmaps, must be done in a worker thread—or in the case of database operations, via an asynchronous request.

See Background work overview for more information about available solutions for scheduling work on a background thread and communicating back with the UI.

ANRs in BroadcastReceiver

BroadcastReceiver execution time is constrained because broadcast receivers are meant to do small, discrete amounts of work in the background, such as saving a setting or registering a Notification. So, as with other methods called in the UI thread, apps must avoid potentially long-running operations or calculations in a broadcast receiver. Instead of doing intensive tasks via worker threads, schedule your app's work for later execution. See the Background work overview for more information about possible solutions.

Another common issue with BroadcastReceiver objects occurs when they execute too frequently. Frequent background execution can reduce the amount of memory available to other apps. For more information about how to enable and disable BroadcastReceiver objects efficiently, see Broadcasts overview.

Reinforce responsiveness

Generally, 100 to 200ms is the threshold beyond which users perceive slowness in an app. Here are additional tips for making your app seem responsive to users:

  • If your app is doing work in the background in response to user input, show that progress is being made, such as with a ProgressBar in your UI.
  • For games specifically, do calculations for moves in a worker thread.
  • If your app has a time-consuming initial setup phase, consider showing a splash screen or rendering the main view as quickly as possible. Indicate that loading is in progress and fill the information asynchronously. In either case, we recommend indicatating somehow that progress is being made, so that the user doesn't perceive that the app is frozen.
  • Use performance tools such as Perfetto and CPU Profiler to determine bottlenecks in your app's responsiveness.