| page.title=Keeping Your App Responsive |
| page.tags=threads,asynctask |
| |
| page.article=true |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| |
| <h2>In this document</h2> |
| <ol class="nolist"> |
| <li><a href="#anr">What Triggers ANR?</a></li> |
| <li><a href="#Avoiding">How to Avoid ANRs</a></li> |
| <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li> |
| </ol> |
| |
| </div> |
| </div> |
| |
| <div class="figure" style="width:280px"> |
| <img src="{@docRoot}images/anr.png" alt=""/> |
| <p class="img-caption"><strong>Figure 1.</strong> An ANR dialog displayed to the user.</p> |
| </div> |
| |
| <p>It's possible to write code that wins every performance test in the world, |
| but still feels sluggish, hang or freeze for significant periods, or take too |
| long to process input. The worst thing that can happen to your app's responsiveness |
| is an "Application Not Responding" (ANR) dialog.</p> |
| |
| <p>In Android, the system guards against applications that are insufficiently |
| responsive for a period of time by displaying a dialog that says your app has |
| stopped responding, such as the dialog |
| in Figure 1. At this point, your app has been unresponsive for a considerable |
| period of time so the system offers the user an option to quit the app. It's critical |
| to design responsiveness into your application so the system never displays |
| an ANR dialog to the user. </p> |
| |
| <p>This document describes how the Android system determines whether an |
| application is not responding and provides guidelines for ensuring that your |
| application stays responsive. </p> |
| |
| |
| <h2 id="anr">What Triggers ANR?</h2> |
| |
| <p>Generally, the system displays an ANR if an application cannot respond to |
| user input. For example, if an application blocks on some I/O operation |
| (frequently a network access) on the UI thread so the system can't |
| process incoming user input events. Or perhaps the 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 always important to make |
| sure these computations are efficient, but even the |
| most efficient code still takes time to run.</p> |
| |
| <p>In any situation in which your app performs a potentially lengthy operation, |
| <strong>you should not perform the work on the UI thread</strong>, but 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 |
| has frozen. Because such threading usually is accomplished at the class |
| level, you can think of responsiveness as a <em>class</em> problem. (Compare |
| this with basic code performance, which is a <em>method</em>-level |
| concern.)</p> |
| |
| <p>In Android, application responsiveness is monitored by the Activity Manager |
| and Window Manager system services. Android will display the ANR dialog |
| for a particular application when it detects one of the following |
| conditions:</p> |
| <ul> |
| <li>No response to an input event (such as key press or screen touch events) |
| within 5 seconds.</li> |
| <li>A {@link android.content.BroadcastReceiver BroadcastReceiver} |
| hasn't finished executing within 10 seconds.</li> |
| </ul> |
| |
| |
| |
| <h2 id="Avoiding">How to Avoid ANRs</h2> |
| |
| <p>Android applications normally run entirely on a single thread by default |
| the "UI thread" or "main thread"). |
| This means anything your application is doing in the UI thread that |
| takes a long time to complete can trigger the ANR dialog because your |
| application is not giving itself a chance to handle the input event or intent |
| broadcasts.</p> |
| |
| <p>Therefore, any method that runs in the UI thread should do as little work |
| as possible on that thread. In particular, activities should do as little as possible to set |
| up in key life-cycle methods such as {@link android.app.Activity#onCreate onCreate()} |
| and {@link android.app.Activity#onResume onResume()}. |
| Potentially long running operations such as network |
| or database operations, or computationally expensive calculations such as |
| resizing bitmaps should be done in a worker thread (or in the case of databases |
| operations, via an asynchronous request).</p> |
| |
| <p>The most effecive way to create a worker thread for longer |
| operations is with the {@link android.os.AsyncTask} |
| class. Simply extend {@link android.os.AsyncTask} and implement the |
| {@link android.os.AsyncTask#doInBackground doInBackground()} method to perform the work. |
| To post progress changes to the user, you can call |
| {@link android.os.AsyncTask#publishProgress publishProgress()}, which invokes the |
| {@link android.os.AsyncTask#onProgressUpdate onProgressUpdate()} callback method. From your |
| implementation of {@link android.os.AsyncTask#onProgressUpdate onProgressUpdate()} (which |
| runs on the UI thread), you can notify the user. For example:</p> |
| |
| <pre> |
| private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { |
| // Do the long-running work in here |
| protected Long doInBackground(URL... urls) { |
| int count = urls.length; |
| long totalSize = 0; |
| for (int i = 0; i < count; i++) { |
| totalSize += Downloader.downloadFile(urls[i]); |
| publishProgress((int) ((i / (float) count) * 100)); |
| // Escape early if cancel() is called |
| if (isCancelled()) break; |
| } |
| return totalSize; |
| } |
| |
| // This is called each time you call publishProgress() |
| protected void onProgressUpdate(Integer... progress) { |
| setProgressPercent(progress[0]); |
| } |
| |
| // This is called when doInBackground() is finished |
| protected void onPostExecute(Long result) { |
| showNotification("Downloaded " + result + " bytes"); |
| } |
| } |
| </pre> |
| |
| <p>To execute this worker thread, simply create an instance and |
| call {@link android.os.AsyncTask#execute execute()}:</p> |
| |
| <pre> |
| new DownloadFilesTask().execute(url1, url2, url3); |
| </pre> |
| |
| |
| <p>Although it's more complicated than {@link android.os.AsyncTask}, you might want to instead |
| create your own {@link java.lang.Thread} or {@link android.os.HandlerThread} class. If you do, |
| you should set the thread priority to "background" priority by calling {@link |
| android.os.Process#setThreadPriority Process.setThreadPriority()} and passing {@link |
| android.os.Process#THREAD_PRIORITY_BACKGROUND}. If you don't set the thread to a lower priority |
| this way, then the thread could still slow down your app because it operates at the same priority |
| as the UI thread by default.</p> |
| |
| <p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread}, |
| be sure that your UI thread does not block while waiting for the worker thread to |
| complete—do not call {@link java.lang.Thread#wait Thread.wait()} or |
| {@link java.lang.Thread#sleep Thread.sleep()}. Instead of blocking while waiting for a worker |
| thread to complete, your main thread should provide a {@link |
| android.os.Handler} for the other threads to post back to upon completion. |
| Designing your application in this way will allow your app's UI thread to remain |
| responsive to input and thus avoid ANR dialogs caused by the 5 second input |
| event timeout.</p> |
| |
| <p>The specific constraint on {@link android.content.BroadcastReceiver} execution time |
| emphasizes what broadcast receivers are meant to do: |
| small, discrete amounts of work in the background such |
| as saving a setting or registering a {@link android.app.Notification}. So as with other methods |
| called in the UI thread, applications should avoid potentially long-running |
| operations or calculations in a broadcast receiver. But instead of doing intensive |
| tasks via worker threads, your |
| application should start an {@link android.app.IntentService} if a |
| potentially long running action needs to be taken in response to an intent |
| broadcast.</p> |
| |
| <p class="note"><strong>Tip:</strong> |
| You can use {@link android.os.StrictMode} to help find potentially |
| long running operations such as network or database operations that |
| you might accidentally be doing your main thread.</p> |
| |
| |
| |
| <h2 id="Reinforcing">Reinforce Responsiveness</h2> |
| |
| <p>Generally, 100 to 200ms is the threshold beyond which users will perceive |
| slowness in an application. As such, here |
| are some additional tips beyond what you should do to avoid ANR and |
| make your application seem responsive to users:</p> |
| |
| <ul> |
| <li>If your application is doing work in the background in response to |
| user input, show that progress is being made (such as with a {@link |
| android.widget.ProgressBar} in your UI).</li> |
| |
| <li>For games specifically, do calculations for moves in a worker |
| thread.</li> |
| |
| <li>If your application 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, you should |
| indicate somehow that progress is being made, lest the user perceive that |
| the application is frozen.</li> |
| |
| <li>Use performance tools such as <a href="{@docRoot}tools/help/systrace.html">Systrace</a> |
| and <a href="{@docRoot}tools/help/traceview.html">Traceview</a> to determine bottlenecks |
| in your app's responsiveness.</li> |
| </ul> |