summaryrefslogtreecommitdiffstats
path: root/docs/html/training/articles/perf-anr.jd
diff options
context:
space:
mode:
Diffstat (limited to 'docs/html/training/articles/perf-anr.jd')
-rw-r--r--docs/html/training/articles/perf-anr.jd196
1 files changed, 196 insertions, 0 deletions
diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
new file mode 100644
index 0000000..864fb34
--- /dev/null
+++ b/docs/html/training/articles/perf-anr.jd
@@ -0,0 +1,196 @@
+page.title=Keeping Your App Responsive
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>In this document</h2>
+<ol>
+ <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&lt;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 &lt; 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&mdash;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>