141 lines
7.1 KiB
Plaintext
141 lines
7.1 KiB
Plaintext
page.title=Designing for Responsiveness
|
|
@jd:body
|
|
|
|
<div id="qv-wrapper">
|
|
<div id="qv">
|
|
|
|
<h2>In this document</h2>
|
|
<ol>
|
|
<li><a href="#anr">What Triggers ANR?</a></li>
|
|
<li><a href="#avoiding">How to Avoid ANR</a></li>
|
|
<li><a href="#reinforcing">Reinforcing Responsiveness</a></li>
|
|
</ol>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="figure">
|
|
<img src="{@docRoot}images/anr.png" alt="Screenshot of ANR dialog box" width="240" height="320"/>
|
|
<p><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 sends users in a fiery rage when they try to use the application.
|
|
These are the applications that aren't <em>responsive</em> enough — the
|
|
ones that feel sluggish, hang or freeze for significant periods, or take too
|
|
long to process input. </p>
|
|
|
|
<p>In Android, the system guards against applications that are insufficiently
|
|
responsive for a period of time by displaying a dialog to the user, called the
|
|
Application Not Responding (ANR) dialog, shown at right in Figure 1. The user
|
|
can choose to let the application continue, but the user won't appreciate having
|
|
to act on this dialog every time he or she uses your application. It's critical
|
|
to design responsiveness into your application, so that the system never has
|
|
cause to display an ANR dialog to the user. </p>
|
|
|
|
<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), then the main application thread won't be able to
|
|
process incoming user input events. After a time, the system concludes that the
|
|
application is frozen, and displays the ANR to give the user the option to kill
|
|
it. </p>
|
|
|
|
<p>Similarly, if your application spends too much time building an elaborate in-memory
|
|
structure, or perhaps computing the next move in a game, the system will
|
|
conclude that your application has hung. It's always important to make
|
|
sure these computations are efficient using the techniques above, but even the
|
|
most efficient code still takes time to run.</p>
|
|
|
|
<p>In both of these cases, the recommended approach is to create a child thread and do
|
|
most of your work there. This keeps the main thread (which drives the user
|
|
interface event loop) running and prevents the system from concluding that your code
|
|
has frozen. Since such threading usually is accomplished at the class
|
|
level, you can think of responsiveness as a <em>class</em> problem. (Compare
|
|
this with basic performance, which was described above as a <em>method</em>-level
|
|
concern.)</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>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 (e.g. key press, screen touch)
|
|
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 ANR</h2>
|
|
|
|
<p>Given the above definition for ANR, let's examine why this can occur in
|
|
Android applications and how best to structure your application to avoid ANR.</p>
|
|
|
|
<p>Android applications normally run entirely on a single (i.e. main) thread.
|
|
This means that anything your application is doing in the main 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
|
|
broadcast.</p>
|
|
|
|
<p>Therefore any method that runs in the main thread should do as little work
|
|
as possible. In particular, Activities should do as little as possible to set
|
|
up in key life-cycle methods such as <code>onCreate()</code> and
|
|
<code>onResume()</code>. Potentially long running operations such as network
|
|
or database operations, or computationally expensive calculations such as
|
|
resizing bitmaps should be done in a child thread (or in the case of databases
|
|
operations, via an asynchronous request). However, this does not mean that
|
|
your main thread should block while waiting for the child thread to
|
|
complete — nor should you call <code>Thread.wait()</code> or
|
|
<code>Thread.sleep()</code>. Instead of blocking while waiting for a child
|
|
thread to complete, your main thread should provide a {@link
|
|
android.os.Handler Handler} for child threads to post back to upon completion.
|
|
Designing your application in this way will allow your main thread to remain
|
|
responsive to input and thus avoid ANR dialogs caused by the 5 second input
|
|
event timeout. These same practices should be followed for any other threads
|
|
that display UI, as they are also subject to the same timeouts.</p>
|
|
|
|
<p>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>
|
|
|
|
<p>The specific constraint on IntentReceiver execution time emphasizes what
|
|
they were meant to do: small, discrete amounts of work in the background such
|
|
as saving a setting or registering a Notification. So as with other methods
|
|
called in the main thread, applications should avoid potentially long-running
|
|
operations or calculations in BroadcastReceivers. But instead of doing intensive
|
|
tasks via child threads (as the life of a BroadcastReceiver is short), your
|
|
application should start a {@link android.app.Service Service} if a
|
|
potentially long running action needs to be taken in response to an Intent
|
|
broadcast. As a side note, you should also avoid starting an Activity from an
|
|
Intent Receiver, as it will spawn a new screen that will steal focus from
|
|
whatever application the user is currently has running. If your application
|
|
has something to show the user in response to an Intent broadcast, it should
|
|
do so using the {@link android.app.NotificationManager Notification
|
|
Manager}.</p>
|
|
|
|
<h2 id="reinforcing">Reinforcing Responsiveness</h2>
|
|
|
|
<p>Generally, 100 to 200ms is the threshold beyond which users will perceive
|
|
lag (or lack of "snappiness," if you will) in an application. As such, here
|
|
are some additional tips beyond what you should do to avoid ANR that will help
|
|
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 ({@link
|
|
android.widget.ProgressBar ProgressBar} and {@link
|
|
android.app.ProgressDialog ProgressDialog} are useful for this).</li>
|
|
<li>For games specifically, do calculations for moves in a child
|
|
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
|
|
and filling in 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>
|
|
</ul>
|