Home | History | Annotate | Download | only in articles
      1 page.title=Keeping Your App Responsive
      2 page.tags=threads,asynctask
      3 
      4 page.article=true
      5 @jd:body
      6 
      7 <div id="tb-wrapper">
      8 <div id="tb">
      9 
     10 <h2>In this document</h2>
     11 <ol class="nolist">
     12   <li><a href="#anr">What Triggers ANR?</a></li>
     13   <li><a href="#Avoiding">How to Avoid ANRs</a></li>
     14   <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li>
     15 </ol>
     16 
     17 <h2>You should also read</h2>
     18 <ul>
     19   <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
     20   <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
     21   <li><a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating Broadcast Receivers On Demand</a>
     22   <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
     23 </ul>
     24 
     25 </div>
     26 </div>
     27 
     28 <div class="figure" style="width:280px">
     29 <img src="{@docRoot}images/anr.png" alt=""/>
     30 <p class="img-caption"><strong>Figure 1.</strong> An ANR dialog displayed to the user.</p>
     31 </div>
     32 
     33 <p>It's possible to write code that wins every performance test in the world,
     34 but still feels sluggish, hang or freeze for significant periods, or take too
     35 long to process input. The worst thing that can happen to your app's responsiveness
     36 is an "Application Not Responding" (ANR) dialog.</p>
     37 
     38 <p>In Android, the system guards against applications that are insufficiently
     39 responsive for a period of time by displaying a dialog that says your app has
     40 stopped responding, such as the dialog
     41 in Figure 1. At this point, your app has been unresponsive for a considerable
     42 period of time so the system offers the user an option to quit the app. It's critical
     43 to design responsiveness into your application so the system never displays
     44 an ANR dialog to the user. </p>
     45 
     46 <p>This document describes how the Android system determines whether an
     47 application is not responding and provides guidelines for ensuring that your
     48 application stays responsive. </p>
     49 
     50 
     51 <h2 id="anr">What Triggers ANR?</h2>
     52 
     53 <p>Generally, the system displays an ANR if an application cannot respond to
     54 user input. For example, if an  application blocks on some I/O operation
     55 (frequently a network access) on the UI thread so the system can't
     56 process incoming user input events. Or perhaps the app
     57 spends too much time building an elaborate in-memory
     58 structure or computing the next move in a game on the UI thread. It's always important to make
     59 sure these computations are efficient, but even the
     60 most efficient code still takes time to run.</p>
     61 
     62 <p>In any situation in which your app performs a potentially lengthy operation,
     63 <strong>you should not perform the work on the UI thread</strong>, but instead create a
     64 worker thread and do most of the work there. This keeps the UI thread (which drives the user
     65 interface event loop) running and prevents the system from concluding that your code
     66 has frozen. Because such threading usually is accomplished at the class
     67 level, you can think of responsiveness as a <em>class</em> problem. (Compare
     68 this with basic code performance, which is a <em>method</em>-level
     69 concern.)</p>
     70 
     71 <p>In Android, application responsiveness is monitored by the Activity Manager
     72 and Window Manager system services. Android will display the ANR dialog
     73 for a particular application when it detects one of the following
     74 conditions:</p>
     75 <ul>
     76     <li>No response to an input event (such as key press or screen touch events)
     77     within 5 seconds.</li>
     78     <li>A {@link android.content.BroadcastReceiver BroadcastReceiver}
     79     hasn't finished executing within 10 seconds.</li>
     80 </ul>
     81 
     82 
     83 
     84 <h2 id="Avoiding">How to Avoid ANRs</h2>
     85 
     86 <p>Android applications normally run entirely on a single thread by default
     87 the "UI thread" or "main thread").
     88 This means anything your application is doing in the UI thread that
     89 takes a long time to complete can trigger the ANR dialog because your
     90 application is not giving itself a chance to handle the input event or intent
     91 broadcasts.</p>
     92 
     93 <p>Therefore, any method that runs in the UI thread should do as little work
     94 as possible on that thread. In particular, activities should do as little as possible to set
     95 up in key life-cycle methods such as {@link android.app.Activity#onCreate onCreate()}
     96 and {@link android.app.Activity#onResume onResume()}.
     97 Potentially long running operations such as network
     98 or database operations, or computationally expensive calculations such as
     99 resizing bitmaps should be done in a worker thread (or in the case of databases
    100 operations, via an asynchronous request).</p>
    101 
    102 <p>The most effective way to create a worker thread for longer
    103 operations is with the {@link android.os.AsyncTask}
    104 class. Simply extend {@link android.os.AsyncTask} and implement the
    105 {@link android.os.AsyncTask#doInBackground doInBackground()} method to perform the work.
    106 To post progress changes to the user, you can call
    107  {@link android.os.AsyncTask#publishProgress publishProgress()}, which invokes the
    108  {@link android.os.AsyncTask#onProgressUpdate onProgressUpdate()} callback method. From your
    109  implementation of {@link android.os.AsyncTask#onProgressUpdate onProgressUpdate()} (which
    110  runs on the UI thread), you can notify the user. For example:</p>
    111 
    112 <pre>
    113 private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long> {
    114     // Do the long-running work in here
    115     protected Long doInBackground(URL... urls) {
    116         int count = urls.length;
    117         long totalSize = 0;
    118         for (int i = 0; i &lt; count; i++) {
    119             totalSize += Downloader.downloadFile(urls[i]);
    120             publishProgress((int) ((i / (float) count) * 100));
    121             // Escape early if cancel() is called
    122             if (isCancelled()) break;
    123         }
    124         return totalSize;
    125     }
    126 
    127     // This is called each time you call publishProgress()
    128     protected void onProgressUpdate(Integer... progress) {
    129         setProgressPercent(progress[0]);
    130     }
    131 
    132     // This is called when doInBackground() is finished
    133     protected void onPostExecute(Long result) {
    134         showNotification("Downloaded " + result + " bytes");
    135     }
    136 }
    137 </pre>
    138 
    139  <p>To execute this worker thread, simply create an instance and
    140  call {@link android.os.AsyncTask#execute execute()}:</p>
    141 
    142 <pre>
    143 new DownloadFilesTask().execute(url1, url2, url3);
    144 </pre>
    145 
    146 
    147 <p>Although it's more complicated than {@link android.os.AsyncTask}, you might want to instead
    148 create your own {@link java.lang.Thread} or {@link android.os.HandlerThread} class. If you do,
    149 you should set the thread priority to "background" priority by calling {@link
    150 android.os.Process#setThreadPriority Process.setThreadPriority()} and passing {@link
    151 android.os.Process#THREAD_PRIORITY_BACKGROUND}. If you don't set the thread to a lower priority
    152 this way, then the thread could still slow down your app because it operates at the same priority
    153 as the UI thread by default.</p>
    154 
    155 <p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread},
    156 be sure that your UI thread does not block while waiting for the worker thread to
    157 complete&mdash;do not call {@link java.lang.Thread#wait Thread.wait()} or
    158 {@link java.lang.Thread#sleep Thread.sleep()}. Instead of blocking while waiting for a worker
    159 thread to complete, your main thread should provide a {@link
    160 android.os.Handler} for the other threads to post back to upon completion.
    161 Designing your application in this way will allow your app's UI thread to remain
    162 responsive to input and thus avoid ANR dialogs caused by the 5 second input
    163 event timeout.</p>
    164 
    165 <p>The specific constraint on {@link android.content.BroadcastReceiver} execution time
    166 emphasizes what broadcast receivers are meant to do:
    167 small, discrete amounts of work in the background such
    168 as saving a setting or registering a {@link android.app.Notification}. So as with other methods
    169 called in the UI thread, applications should avoid potentially long-running
    170 operations or calculations in a broadcast receiver. But instead of doing intensive
    171 tasks via worker threads, your
    172 application should start an {@link android.app.IntentService} if a
    173 potentially long running action needs to be taken in response to an intent
    174 broadcast.</p>
    175 
    176 <p>
    177   Another common issue with {@link android.content.BroadcastReceiver} objects
    178   occurs when they execute too frequently. Frequent background execution can
    179   reduce the amount of memory available to other apps.
    180   For more information about how to enable and disable
    181   {@link android.content.BroadcastReceiver} objects efficiently, see
    182   <a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating
    183     Broadcast Receivers on Demand</a>.
    184 </p>
    185 
    186 <p class="note"><strong>Tip:</strong>
    187 You can use {@link android.os.StrictMode} to help find potentially
    188 long running operations such as network or database operations that
    189 you might accidentally be doing on your main thread.</p>
    190 
    191 
    192 
    193 <h2 id="Reinforcing">Reinforce Responsiveness</h2>
    194 
    195 <p>Generally, 100 to 200ms is the threshold beyond which users will perceive
    196 slowness in an application. As such, here
    197 are some additional tips beyond what you should do to avoid ANR and
    198 make your application seem responsive to users:</p>
    199 
    200 <ul>
    201     <li>If your application is doing work in the background in response to
    202     user input, show that progress is being made (such as with a {@link
    203     android.widget.ProgressBar} in your UI).</li>
    204 
    205     <li>For games specifically, do calculations for moves in a worker
    206     thread.</li>
    207 
    208     <li>If your application has a time-consuming initial setup phase, consider
    209     showing a splash screen or rendering the main view as quickly as possible, indicate that
    210     loading is in progress and fill the information asynchronously. In either case, you should
    211     indicate somehow that progress is being made, lest the user perceive that
    212     the application is frozen.</li>
    213 
    214     <li>Use performance tools such as <a href="{@docRoot}tools/help/systrace.html">Systrace</a>
    215     and <a href="{@docRoot}tools/help/traceview.html">Traceview</a> to determine bottlenecks
    216     in your app's responsiveness.</li>
    217 </ul>
    218