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