blob: 87cfc1c985bda80eaf0008117fb12de7b5505477 [file] [log] [blame]
Scott Main22cc2762012-11-07 16:35:16 -08001page.title=Keeping Your App Responsive
Scott Main1c2dea02013-04-10 18:59:29 -07002page.tags="threads","asynctask"
3
Dirk Doughertyd5894212012-11-28 18:53:10 -08004page.article=true
Scott Main22cc2762012-11-07 16:35:16 -08005@jd:body
6
7<div id="tb-wrapper">
8<div id="tb">
9
10<h2>In this document</h2>
Scott Maina3f0e012013-09-19 17:45:40 -070011<ol class="nolist">
Scott Main22cc2762012-11-07 16:35:16 -080012 <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,
26but still feels sluggish, hang or freeze for significant periods, or take too
27long to process input. The worst thing that can happen to your app's responsiveness
28is an "Application Not Responding" (ANR) dialog.</p>
29
30<p>In Android, the system guards against applications that are insufficiently
31responsive for a period of time by displaying a dialog that says your app has
32stopped responding, such as the dialog
33in Figure 1. At this point, your app has been unresponsive for a considerable
34period of time so the system offers the user an option to quit the app. It's critical
35to design responsiveness into your application so the system never displays
36an ANR dialog to the user. </p>
37
38<p>This document describes how the Android system determines whether an
39application is not responding and provides guidelines for ensuring that your
40application 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
46user 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
48process incoming user input events. Or perhaps the app
49spends too much time building an elaborate in-memory
50structure or computing the next move in a game on the UI thread. It's always important to make
51sure these computations are efficient, but even the
52most 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
56worker thread and do most of the work there. This keeps the UI thread (which drives the user
57interface event loop) running and prevents the system from concluding that your code
58has frozen. Because such threading usually is accomplished at the class
59level, you can think of responsiveness as a <em>class</em> problem. (Compare
60this with basic code performance, which is a <em>method</em>-level
61concern.)</p>
62
63<p>In Android, application responsiveness is monitored by the Activity Manager
64and Window Manager system services. Android will display the ANR dialog
65for a particular application when it detects one of the following
66conditions:</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
79the "UI thread" or "main thread").
80This means anything your application is doing in the UI thread that
81takes a long time to complete can trigger the ANR dialog because your
82application is not giving itself a chance to handle the input event or intent
83broadcasts.</p>
84
85<p>Therefore, any method that runs in the UI thread should do as little work
86as possible on that thread. In particular, activities should do as little as possible to set
87up in key life-cycle methods such as {@link android.app.Activity#onCreate onCreate()}
88and {@link android.app.Activity#onResume onResume()}.
89Potentially long running operations such as network
90or database operations, or computationally expensive calculations such as
91resizing bitmaps should be done in a worker thread (or in the case of databases
92operations, via an asynchronous request).</p>
93
94<p>The most effecive way to create a worker thread for longer
95operations is with the {@link android.os.AsyncTask}
96class. Simply extend {@link android.os.AsyncTask} and implement the
97{@link android.os.AsyncTask#doInBackground doInBackground()} method to perform the work.
98To 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>
105private class DownloadFilesTask extends AsyncTask&lt;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 &lt; 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>
135new 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
140create your own {@link java.lang.Thread} or {@link android.os.HandlerThread} class. If you do,
141you should set the thread priority to "background" priority by calling {@link
142android.os.Process#setThreadPriority Process.setThreadPriority()} and passing {@link
143android.os.Process#THREAD_PRIORITY_BACKGROUND}. If you don't set the thread to a lower priority
144this way, then the thread could still slow down your app because it operates at the same priority
145as the UI thread by default.</p>
146
147<p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread},
148be sure that your UI thread does not block while waiting for the worker thread to
149complete&mdash;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
151thread to complete, your main thread should provide a {@link
152android.os.Handler} for the other threads to post back to upon completion.
153Designing your application in this way will allow your app's UI thread to remain
154responsive to input and thus avoid ANR dialogs caused by the 5 second input
155event timeout.</p>
156
157<p>The specific constraint on {@link android.content.BroadcastReceiver} execution time
158emphasizes what broadcast receivers are meant to do:
159small, discrete amounts of work in the background such
160as saving a setting or registering a {@link android.app.Notification}. So as with other methods
161called in the UI thread, applications should avoid potentially long-running
162operations or calculations in a broadcast receiver. But instead of doing intensive
163tasks via worker threads, your
164application should start an {@link android.app.IntentService} if a
165potentially long running action needs to be taken in response to an intent
166broadcast.</p>
167
168<p class="note"><strong>Tip:</strong>
169You can use {@link android.os.StrictMode} to help find potentially
170long running operations such as network or database operations that
171you 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
178slowness in an application. As such, here
179are some additional tips beyond what you should do to avoid ANR and
180make 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>