diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /docs/html/guide/practices/design | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'docs/html/guide/practices/design')
-rw-r--r-- | docs/html/guide/practices/design/index.jd | 21 | ||||
-rw-r--r-- | docs/html/guide/practices/design/performance.jd | 549 | ||||
-rw-r--r-- | docs/html/guide/practices/design/responsiveness.jd | 117 | ||||
-rw-r--r-- | docs/html/guide/practices/design/seamlessness.jd | 245 |
4 files changed, 932 insertions, 0 deletions
diff --git a/docs/html/guide/practices/design/index.jd b/docs/html/guide/practices/design/index.jd new file mode 100644 index 0000000..a818831 --- /dev/null +++ b/docs/html/guide/practices/design/index.jd @@ -0,0 +1,21 @@ +page.title=Application Design Goals +@jd:body + +<p>When learning how to build applications on a new platform, you first learn what APIs are available and how to use them. Later, you learn the nuances of the platform. Put another way: first you learn how you <em>can</em> build applications; later, you learn how you <em>should</em> build them, to ensure that your applications offer outstanding performance and a great user experience. </p> + +<p>The documents below help you learn the nuances of Android and get started building great applications more quickly, They discuss important aspects of application design that directly influence the user experience of your application, when in the hands of a mobile device user. You should read and consider these design goals as you plan your application and throughout its development, especially if you are new to developing for mobile devices.</p> + +<p>Successful mobile applications offer an outstanding user experience, in addition to a compelling technical feature set. The user experience is more than just its visual design or UI flow. It is also influenced by how well the application responds to the user's keypresses and other actions, how it well it interacts with other applications, and how fully and efficiently it uses device and system capabilities.</p> + +<p>An outstanding user experience has three key characteristics: it is +<em>fast</em>; it is <em>responsive</em>; and it is <em>seamless</em>. Of course +every platform since the dawn of computing has probably cited those same three +qualities at one time or another. However, each platform achieves them in +different ways; the documents below explain how you can build Android +applications that are fast, responsive, and seamless. </p> + +<ul> +<li><a href="performance.html">Designing for Performance</a> (writing efficient Android code)</a></li> +<li><a href="responsiveness.html">Designing for Responsiveness</a> (avoiding ANR)</a></li> +<li><a href="seamlessness.html">Designing for Seamlessness</a> (coexisting with other applications)</a></li> +</ul> diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd new file mode 100644 index 0000000..1eef342 --- /dev/null +++ b/docs/html/guide/practices/design/performance.jd @@ -0,0 +1,549 @@ +page.title=Designing for Performance +@jd:body + +<p>An Android application should be fast. Well, it's probably more accurate to +say that it should be <em>efficient</em>. That is, it should execute as +efficiently as possible in the mobile device environment, with its limited +computing power and data storage, smaller screen, and constrained battery life. + +<p>As you develop your application, keep in mind that, while the application may +perform well enough in your emulator, running on your dual-core development +computer, it will not perform that well when run a mobile device — even +the most powerful mobile device can't match the capabilities of a typical +desktop system. For that reason, you should strive to write efficient code, to +ensure the best possible performance on a variety of mobile devices.</p> + +<p>Generally speaking, writing fast or efficient code means keeping memory +allocations to a minimum, writing tight code, and avoiding certain language and +programming idioms that can subtly cripple performance. In object-oriented +terms, most of this work takes place at the <em>method</em> level, on the order of +actual lines of code, loops, and so on.</p> + +<p>This document covers these topics: </p> +<ul> + <li><a href="#intro">Introduction</a></li> + <li><a href="#object_creation">Avoid Creating Objects</a></li> + <li><a href="#native_methods">Use Native Methods</a></li> + <li><a href="#prefer_virtual">Prefer Virtual Over Interface</a></li> + <li><a href="#prefer_static">Prefer Static Over Virtual</a></li> + <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li> + <li><a href="#cache_fields">Cache Field Lookups</a></li> + <li><a href="#use_final">Declare Constants Final</a></li> + <li><a href="#foreach">Use Enhanced For Loop Syntax With Caution</a></li> + <li><a href="#avoid_enums">Avoid Enums</a></li> + <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li> + <li><a href="#avoidfloat">Avoid Float</a> </li> + <li><a href="#samples">Some Sample Performance Numbers</a> </li> + <li><a href="#closing_notes">Closing Notes</a></li> +</ul> + +<a name="intro" id="intro"></a> +<h2>Introduction</h2> + +<p>There are two basic rules for resource-constrained systems:</p> + +<ul> + <li>Don't do work that you don't need to do.</li> + <li>Don't allocate memory if you can avoid it.</li> +</ul> + +<p>All the tips below follow from these two basic tenets.</p> + +<p>Some would argue that much of the advice on this page amounts to "premature +optimization." While it's true that micro-optimizations sometimes make it +harder to develop efficient data structures and algorithms, on embedded +devices like handsets you often simply have no choice. For instance, if you +bring your assumptions about VM performance on desktop machines to Android, +you're quite likely to write code that exhausts system memory. This will bring +your application to a crawl — let alone what it will do to other programs +running on the system!</p> + +<p>That's why these guidelines are important. Android's success depends on +the user experience that your applications provide, and that user experience +depends in part on whether your code is responsive and snappy, or slow and +aggravating. Since all our applications will run on the same devices, we're +all in this together, in a way. Think of this document as like the rules of +the road you had to learn when you got your driver's license: things run +smoothly when everybody follows them, but when you don't, you get your car +smashed up.</p> + +<p>Before we get down to brass tacks, a brief observation: nearly all issues +described below are valid whether or not the VM features a JIT compiler. If I +have two methods that accomplish the same thing, and the interpreted execution +of foo() is faster than bar(), then the compiled version of foo() will +probably be as fast or faster than compiled bar(). It is unwise to rely on a +compiler to "save" you and make your code fast enough.</p> + +<a name="object_creation"></a> +<h2>Avoid Creating Objects</h2> + +<p>Object creation is never free. A generational GC with per-thread allocation +pools for temporary objects can make allocation cheaper, but allocating memory +is always more expensive than not allocating memory.</p> + +<p>If you allocate objects in a user interface loop, you will force a periodic +garbage collection, creating little "hiccups" in the user experience.</p> + +<p>Thus, you should avoid creating object instances you don't need to. Some +examples of things that can help:</p> + +<ul> + <li>When extracting strings from a set of input data, try + to return a substring of the original data, instead of creating a copy. + You will create a new String object, but it will share the char[] + with the data.</li> + <li>If you have a method returning a string, and you know that its result + will always be appended to a StringBuffer anyway, change your signature + and implementation so that the function does the append directly, + instead of creating a short-lived temporary object.</li> +</ul> + +<p>A somewhat more radical idea is to slice up multidimensional arrays into parallel +single one-dimension arrays:</p> + +<ul> + <li>An array of ints is a much better than an array of Integers, + but this also generalizes to the fact that two parallel arrays of ints + are also a <strong>lot</strong> more efficient than an array of (int,int) + objects. The same goes for any combination of primitive types.</li> + <li>If you need to implement a container that stores tuples of (Foo,Bar) + objects, try to remember that two parallel Foo[] and Bar[] arrays are + generally much better than a single array of custom (Foo,Bar) objects. + (The exception to this, of course, is when you're designing an API for + other code to access; in those cases, it's usually better to trade + correct API design for a small hit in speed. But in your own internal + code, you should try and be as efficient as possible.)</li> +</ul> + +<p>Generally speaking, avoid creating short-term temporary objects if you +can. Fewer objects created mean less-frequent garbage collection, which has +a direct impact on user experience.</p> + +<a name="native_methods" id="native_methods"></a> +<h2>Use Native Methods</h2> + +<p>When processing strings, don't hesitate to use specialty methods like +String.indexOf(), String.lastIndexOf(), and their cousins. These are typically +implemented in C/C++ code that easily runs 10-100x faster than doing the same +thing in a Java loop.</p> + +<p>The flip side of that advice is that punching through to a native +method is more expensive than calling an interpreted method. Don't use native +methods for trivial computation, if you can avoid it.</p> + +<a name="prefer_virtual" id="prefer_virtual"></a> +<h2>Prefer Virtual Over Interface</h2> + +<p>Suppose you have a HashMap object. You can declare it as a HashMap or as +a generic Map:</p> + +<pre>Map myMap1 = new HashMap(); +HashMap myMap2 = new HashMap();</pre> + +<p>Which is better?</p> + +<p>Conventional wisdom says that you should prefer Map, because it +allows you to change the underlying implementation to anything that +implements the Map interface. Conventional wisdom is correct for +conventional programming, but isn't so great for embedded systems. Calling +through an interface reference can take 2x longer than a virtual +method call through a concrete reference.</p> + +<p>If you have chosen a HashMap because it fits what you're doing, there +is little value in calling it a Map. Given the availability of +IDEs that refactor your code for you, there's not much value in calling +it a Map even if you're not sure where the code is headed. (Again, though, +public APIs are an exception: a good API usually trumps small performance +concerns.)</p> + +<a name="prefer_static" id="prefer_static"></a> +<h2>Prefer Static Over Virtual</h2> + +<p>If you don't need to access an object's fields, make your method static. It can +be called faster, because it doesn't require a virtual method table +indirection. It's also good practice, because you can tell from the method +signature that calling the method can't alter the object's state.</p> + +<a name="internal_get_set" id="internal_get_set"></a> +<h2>Avoid Internal Getters/Setters</h2> + +<p>In native languages like C++ it's common practice to use getters (e.g. +<code>i = getCount()</code>) instead of accessing the field directly (<code>i += mCount</code>). This is an excellent habit for C++, because the compiler can +usually inline the access, and if you need to restrict or debug field access +you can add the code at any time.</p> + +<p>On Android, this is a bad idea. Virtual method calls are expensive, +much more so than instance field lookups. It's reasonable to follow +common object-oriented programming practices and have getters and setters +in the public interface, but within a class you should always access +fields directly.</p> + +<a name="cache_fields" id="cache_fields"></a> +<h2>Cache Field Lookups</h2> + +<p>Accessing object fields is much slower than accessing local variables. +Instead of writing:</p> +<pre>for (int i = 0; i < this.mCount; i++) + dumpItem(this.mItems[i]);</pre> + +<p>You should write:</p> +<pre> int count = this.mCount; + Item[] items = this.mItems; + + for (int i = 0; i < count; i++) + dumpItems(items[i]); +</pre> + +<p>(We're using an explicit "this" to make it clear that these are +member variables.)</p> + +<p>A similar guideline is never call a method in the second clause of a "for" +statement. For example, the following code will execute the getCount() method +once per iteration, which is a huge waste when you could have simply cached +the value as an int:</p> + +<pre>for (int i = 0; i < this.getCount(); i++) + dumpItems(this.getItem(i)); +</pre> + +<p>It's also usually a good idea to create a local variable if you're going to be +accessing an instance field more than once. For example:</p> + +<pre> + protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) { + if (isHorizontalScrollBarEnabled()) { + int size = <strong>mScrollBar</strong>.getSize(<em>false</em>); + if (size <= 0) { + size = mScrollBarSize; + } + <strong>mScrollBar</strong>.setBounds(0, <em>height</em> - size, width, height); + <strong>mScrollBar</strong>.setParams( + computeHorizontalScrollRange(), + computeHorizontalScrollOffset(), + computeHorizontalScrollExtent(), <em>false</em>); + <strong>mScrollBar</strong>.draw(canvas); + } + }</pre> + +<p>That's four separate lookups of the member field <code>mScrollBar</code>. +By caching mScrollBar in a local stack variable, the four member field lookups +become four stack variable references, which are much more efficient.</p> + +<p>Incidentally, method arguments have the same performance characteristics +as local variables.</p> + +<a name="use_final" id="use_final"></a> +<h2>Declare Constants Final</h2> + +<p>Consider the following declaration at the top of a class:</p> + +<pre>static int intVal = 42; +static String strVal = "Hello, world!";</pre> + +<p>The compiler generates a class initializer method, called +<code><clinit></code>, that is executed when the class is first used. +The method stores the value 42 into <code>intVal</code>, and extracts a +reference from the classfile string constant table for <code>strVal</code>. +When these values are referenced later on, they are accessed with field +lookups.</p> + +<p>We can improve matters with the "final" keyword:</p> + +<pre>static final int intVal = 42; +static final String strVal = "Hello, world!";</pre> + +<p>The class no longer requires a <code><clinit></code> method, +because the constants go into classfile static field initializers, which are +handled directly by the VM. Code accessing <code>intVal</code> will use +the integer value 42 directly, and accesses to <code>strVal</code> will +use a relatively inexpensive "string constant" instruction instead of a +field lookup.</p> + +<p>Declaring a method or class "final" does not confer any immediate +performance benefits, but it does allow certain optimizations. For example, if +the compiler knows that a "getter" method can't be overridden by a sub-class, +it can inline the method call.</p> + +<p>You can also declare local variables final. However, this has no definitive +performance benefits. For local variables, only use "final" if it makes the +code clearer (or you have to, e.g. for use in an anonymous inner class).</p> + +<a name="foreach" id="foreach"></a> +<h2>Use Enhanced For Loop Syntax With Caution</h2> + +<p>The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections that implement the Iterable interface. +With these objects, an iterator is allocated to make interface calls +to hasNext() and next(). With an ArrayList, you're better off walking through +it directly, but for other collections the enhanced for loop syntax will be equivalent +to explicit iterator usage.</p> + +<p>Nevertheless, the following code shows an acceptable use of the enhanced for loop:</p> + +<pre>public class Foo { + int mSplat; + static Foo mArray[] = new Foo[27]; + + public static void zero() { + int sum = 0; + for (int i = 0; i < mArray.length; i++) { + sum += mArray[i].mSplat; + } + } + + public static void one() { + int sum = 0; + Foo[] localArray = mArray; + int len = localArray.length; + + for (int i = 0; i < len; i++) { + sum += localArray[i].mSplat; + } + } + + public static void two() { + int sum = 0; + for (Foo a: mArray) { + sum += a.mSplat; + } + } +}</pre> + +<p><strong>zero()</strong> retrieves the static field twice and gets the array +length once for every iteration through the loop.</p> + +<p><strong>one()</strong> pulls everything out into local variables, avoiding +the lookups.</p> + +<p><strong>two()</strong> uses the enhanced for loop syntax introduced in version 1.5 of +the Java programming language. The code generated by the compiler takes care +of copying the array reference and the array length to local variables, making +it a good choice for walking through all elements of an array. It does +generate an extra local load/store in the main loop (apparently preserving +"a"), making it a teensy bit slower and 4 bytes longer than one().</p> + +<p>To summarize all that a bit more clearly: enhanced for loop syntax performs well +with arrays, but be cautious when using it with Iterable objects since there is +additional object creation.</p> + +<a name="avoid_enums" id="avoid_enums"></a> +<h2>Avoid Enums</h2> + +<p>Enums are very convenient, but unfortunately can be painful when size +and speed matter. For example, this:</p> + +<pre>public class Foo { + public enum Shrubbery { GROUND, CRAWLING, HANGING } +}</pre> + +<p>turns into a 900 byte .class file (Foo$Shrubbery.class). On first use, the +class initializer invokes the <init> method on objects representing each +of the enumerated values. Each object gets its own static field, and the full +set is stored in an array (a static field called "$VALUES"). That's a lot of +code and data, just for three integers.</p> + +<p>This:</p> + +<pre>Shrubbery shrub = Shrubbery.GROUND;</pre> + +<p>causes a static field lookup. If "GROUND" were a static final int, +the compiler would treat it as a known constant and inline it.</p> + +<p>The flip side, of course, is that with enums you get nicer APIs and +some compile-time value checking. So, the usual trade-off applies: you should +by all means use enums for public APIs, but try to avoid them when performance +matters.</p> + +<p>In some circumstances it can be helpful to get enum integer values +through the <code>ordinal()</code> method. For example, replace:</p> + +<pre>for (int n = 0; n < list.size(); n++) { + if (list.items[n].e == MyEnum.VAL_X) + // do stuff 1 + else if (list.items[n].e == MyEnum.VAL_Y) + // do stuff 2 +}</pre> + +<p>with:</p> + +<pre> int valX = MyEnum.VAL_X.ordinal(); + int valY = MyEnum.VAL_Y.ordinal(); + int count = list.size(); + MyItem items = list.items(); + + for (int n = 0; n < count; n++) + { + int valItem = items[n].e.ordinal(); + + if (valItem == valX) + // do stuff 1 + else if (valItem == valY) + // do stuff 2 + }</pre> + +<p>In some cases, this will be faster, though this is not guaranteed.</p> + +<a name="package_inner" id="package_inner"></a> +<h2>Use Package Scope with Inner Classes</h2> + +<p>Consider the following class definition:</p> + +<pre>public class Foo { + private int mValue; + + public void run() { + Inner in = new Inner(); + mValue = 27; + in.stuff(); + } + + private void doStuff(int value) { + System.out.println("Value is " + value); + } + + private class Inner { + void stuff() { + Foo.this.doStuff(Foo.this.mValue); + } + } +}</pre> + +<p>The key things to note here are that we define an inner class (Foo$Inner) +that directly accesses a private method and a private instance field +in the outer class. This is legal, and the code prints "Value is 27" as +expected.</p> + +<p>The problem is that Foo$Inner is technically (behind the scenes) a totally +separate class, which makes direct access to Foo's private +members illegal. To bridge that gap, the compiler generates a +couple of synthetic methods:</p> + +<pre>/*package*/ static int Foo.access$100(Foo foo) { + return foo.mValue; +} +/*package*/ static void Foo.access$200(Foo foo, int value) { + foo.doStuff(value); +}</pre> + +<p>The inner-class code calls these static methods whenever it needs to +access the "mValue" field or invoke the "doStuff" method in the outer +class. What this means is that the code above really boils down to a case +where you're accessing member fields through accessor methods instead of +directly. Earlier we talked about how accessors are slower than direct field +accesses, so this is an example of a certain language idiom resulting in an +"invisible" performance hit.</p> + +<p>We can avoid this problem by declaring fields and methods accessed +by inner classes to have package scope, rather than private scope. +This runs faster and removes the overhead of the generated methods. +(Unfortunately it also means the fields could be accessed directly by other +classes in the same package, which runs counter to the standard OO +practice of making all fields private. Once again, if you're +designing a public API you might want to carefully consider using this +optimization.)</p> + +<a name="avoidfloat" id="avoidfloat"></a> +<h2>Avoid Float</h2> + +<p>Before the release of the Pentium CPU, it was common for game authors to do +as much as possible with integer math. With the Pentium, the floating point +math co-processor became a built-in feature, and by interleaving integer and +floating-point operations your game would actually go faster than it would +with purely integer math. The common practice on desktop systems is to use +floating point freely.</p> + +<p>Unfortunately, embedded processors frequently do not have hardware floating +point support, so all operations on "float" and "double" are performed in +software. Some basic floating point operations can take on the order of a +millisecond to complete.</p> + +<p>Also, even for integers, some chips have hardware multiply but lack +hardware divide. In such cases, integer division and modulus operations are +performed in software — something to think about if you're designing a +hash table or doing lots of math.</p> + +<a name="samples" id="samples"></a> +<h2>Some Sample Performance Numbers</h2> + +<p>To illustrate some of our ideas, here is a table listing the approximate +run times for a few basic actions. Note that these values should NOT be taken +as absolute numbers: they are a combination of CPU and wall clock time, and +will change as improvements are made to the system. However, it is worth +noting how these values apply relative to each other — for example, +adding a member variable currently takes about four times as long as adding a +local variable.</p> + +<table> + <tr> + <th>Action</th> + <th>Time</th> + </tr> + <tr> + <td>Add a local variable </td> + <td>1</td> + </tr> + <tr class="alt"> + <td>Add a member variable </td> + <td>4</td> + </tr> + <tr> + <td>Call String.length()</td> + <td>5</td> + </tr> + <tr class="alt"> + <td>Call empty static native method</td> + <td>5</td> + </tr> + <tr> + <td>Call empty static method </td> + <td>12</td> + </tr> + <tr class="alt"> + <td>Call empty virtual method </td> + <td>12.5</td> + </tr> + <tr> + <td>Call empty interface method </td> + <td>15</td> + </tr> + <tr class="alt"> + <td>Call Iterator:next() on a HashMap </td> + <td>165</td> + </tr> + <tr> + <td>Call put() on a HashMap</td> + <td>600</td> + </tr> + <tr class="alt"> + <td>Inflate 1 View from XML </td> + <td>22,000</td> + </tr> + <tr> + <td>Inflate 1 LinearLayout containing 1 TextView </td> + <td>25,000</td> + </tr> + <tr class="alt"> + <td>Inflate 1 LinearLayout containing 6 View objects </td> + <td>100,000</td> + </tr> + <tr> + <td>Inflate 1 LinearLayout containing 6 TextView objects </td> + <td>135,000</td> + </tr> + <tr class="alt"> + <td>Launch an empty activity </td> + <td>3,000,000</td> + </tr> +</table> + +<a name="closing_notes" id="closing_notes"></a> +<h2>Closing Notes</h2> + +<p>The best way to write good, efficient code for embedded systems is to +understand what the code you write really does. If you really want to allocate +an iterator, by all means use enhanced for loop syntax on a List; just make it a +deliberate choice, not an inadvertent side effect.</p> + +<p>Forewarned is forearmed! Know what you're getting into! Insert your +favorite maxim here, but always think carefully about what your code is doing, +and be on the lookout for ways to speed it up.</p> diff --git a/docs/html/guide/practices/design/responsiveness.jd b/docs/html/guide/practices/design/responsiveness.jd new file mode 100644 index 0000000..e0d1864 --- /dev/null +++ b/docs/html/guide/practices/design/responsiveness.jd @@ -0,0 +1,117 @@ +page.title=Designing for Responsiveness +@jd:body + +<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. 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. So it's important to design responsiveness into your application, so that the system never has cause to display an ANR 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 has hung, and displays the ANR to give the user the option to kill it. + +<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 fix is usually 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 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> + +<div class="sidebox" style="margin-top:1em;border:0;"> +<div style="border:0;background-color:#fff;padding:15px;padding-right:2em;margin:0;"> +<img src="/android/images/anr.png" width="240" height="320" alt="Screenshot of ANR dialog box"> +<p style="margin-top:.5em;padding:.5em;">An ANR dialog displayed to the user.</p> +</div> +</div> + +<p>This document discusses how the Android system determines whether an application is +not responding and provides guidelines for +ensuring that your application is responsive. </p> + +<p>This document covers these topics: </p> +<ul> + <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> +</ul> + +<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>The specific constraint on IntentReciever 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> diff --git a/docs/html/guide/practices/design/seamlessness.jd b/docs/html/guide/practices/design/seamlessness.jd new file mode 100644 index 0000000..4d1dab0 --- /dev/null +++ b/docs/html/guide/practices/design/seamlessness.jd @@ -0,0 +1,245 @@ +page.title=Designing for Seamlessness +@jd:body + +<p>Even if your application is fast and responsive, certain design decisions can +still cause problems for users — because of unplanned interactions with +other applications or dialogs, inadvertent loss of data, unintended blocking, +and so on. To avoid these problems, it helps to understand the context in which +your applications run and the system interactions that can affect your +application. In short, you should strive to develop an application that +interacts seamlessly with the system and with other applications. </p> + +<p>A common seamlessness problem is when an application's background process +— for example, a service or broadcast receiver — pops up a dialog in +response to some event. This may seem like harmless behavior, especially when +you are building and testing your application in isolation, on the emulator. +However, when your application is run on an actual device, your application may +not have user focus at the time your background process displays the dialog. So +it could end up that your application would display it's dialog behind the +active application, or it could take focus from the current application and +display the dialog in front of whatever the user was doing (such as dialing a +phone call, for example). That behavior would not work for your application or +for the user. </p> + +<p>To avoid these problems, your application should use the proper system +facility for notifying the user — the +{@link android.app.Notification Notification} classes. Using +notifications, your application can signal the user that an event has +taken place, by displaying an icon in the status bar rather than taking +focus and interrupting the user.</p> + +<p>Another example of a seamlessness problem is when an activity inadvertently +loses state or user data because it doesn't correctly implement the onPause() +and other lifecycle methods. Or, if your application exposes data intended to be +used by other applications, you should expose it via a ContentProvider, rather +than (for example) doing so through a world-readable raw file or database.</p> + +<p>What those examples have in common is that they involve cooperating nicely +with the system and other applications. The Android system is designed to treat +applications as a sort of federation of loosely-coupled components, rather than +chunks of black-box code. This allows you as the developer to view the entire +system as just an even-larger federation of these components. This benefits you +by allowing you to integrate cleanly and seamlessly with other applications, and +so you should design your own code to return the favor.</p> + +<p>This document discusses common seamlessness problems and how to avoid them. +It covers these topics: </p> +<ul> + <li><a href="#drop">Don't Drop Data</a></li> + <li><a href="#expose">Don't Expose Raw Data</a></li> + <li><a href="#interrupt">Don't Interrupt the User</a></li> + <li><a href="#threads">Got a Lot to Do? Do it in a Thread</a></li> + <li><a href="#multiple-activities">Don't Overload a Single Activity Screen</a></li> + <li><a href="#themes">Extend System Themes</a></li> + <li><a href="#flexui">Design Your UI to Work with Multiple Screen Resolutions</a></li> + <li><a href="#network">Assume the Network is Slow</a></li> + <li><a href="#keyboard">Don't Assume Touchscreen or Keyboard</a></li> + <li><a href="#battery">Do Conserve the Device Battery</a></li> +</ul> + +<h2 id="drop">Don't Drop Data</h2> + +<p>Always keep in mind that Android is a mobile platform. It may seem obvious to +say it, but it's important to remember that another Activity (such as the +"Incoming Phone Call" app) can pop up over your own Activity at any moment. +This will fire the onSaveInstanceState() and onPause() methods, and will likely result in +your application being killed.</p> + +<p>If the user was editing data in your application when the other Activity +appeared, your application will likely lose that data when your application is +killed. Unless, of course, you save the work in progress first. The "Android +Way" is to do just that: Android applications that accept or edit input should +override the onSaveInstanceState() method and save their state in some appropriate +fashion. When the user revisits the application, she should be able to +retrieve her data.</p> + +<p>A classic example of a good use of this behavior is a mail application. If the +user was composing an email when another Activity started up, the application +should save the in-process email as a draft.</p> + +<h2 id="expose">Don't Expose Raw Data</h2> + +<p>If you wouldn't walk down the street in your underwear, neither should your +data. While it's possible to expose certain kinds of application to the world +to read, this is usually not the best idea. Exposing raw data requires other +applications to understand your data format; if you change that format, you'll +break any other applications that aren't similarly updated.</p> + +<p>The "Android Way" is to create a ContentProvider to expose your data to other +applications via a clean, well-thought-out, and maintainable API. Using a +ContentProvider is much like inserting a Java language interface to split up and +componentize two tightly-coupled pieces of code. This means you'll be able to +modify the internal format of your data without changing the interface exposed +by the ContentProvider, and this without affecting other applications.</p> + +<h2 id="interrupt">Don't Interrupt the User</h2> + +<p>If the user is running an application (such as the Phone application during a +call) it's a pretty safe bet he did it on purpose. That's why you should avoid +spawning activities except in direct response to user input from the current +Activity.</p> + +<p>That is, don't call startActivity() from BroadcastReceivers or Services running in +the background. Doing so will interrupt whatever application is currently +running, and result in an annoyed user. Perhaps even worse, your Activity may +become a "keystroke bandit" and receive some of the input the user was in the +middle of providing to the previous Activity. Depending on what your +application does, this could be bad news.</p> + +<p>Instead of spawning Activity UIs directly from the background, you should +instead use the NotificationManager to set Notifications. These will appear in +the status bar, and the user can then click on them at his leisure, to see +what your application has to show him.</p> + +<p>(Note that all this doesn't apply to cases where your own Activity is already +in the foreground: in that case, the user expects to see your next Activity in +response to input.)</p> + +<h2 id="threads">Got a Lot to Do? Do it in a Thread</h2> + +<p>If your application needs to perform some expensive or long-running +computation, you should probably move it to a thread. This will prevent the +dreaded "Application Not Responding" dialog from being displayed to the user, +with the ultimate result being the fiery demise of your application.</p> + +<p>By default, all code in an Activity as well as all its Views run in the same +thread. This is the same thread that also handles UI events. For example, when +the user presses a key, a key-down event is added to the Activity's main +thread's queue. The event handler system needs to dequeue and handle that +event quickly; if it doesn't, the system concludes after a few seconds that +the application is hung and offers to kill it for the user.</p> + +<p>If you have long-running code, running it inline in your Activity will run it +on the event handler thread, effectively blocking the event handler. This will +delay input processing, and result in the ANR dialogs. To avoid this, move +your computations to a thread. This <a +href="responsiveness.html">Design for Responsiveness</a> document +discusses how to do that..</p> + +<h2 id="multiple-activities">Don't Overload a Single Activity Screen</h2> + +<p>Any application worth using will probably have several different screens. +When designing the screens of your UI, be sure to make use of multiple Activity +object instances.</p> + +<p>Depending on your development background, you may interpret an Activity as +similar to something like a Java Applet, in that it is the entry point for +your application. However, that's not quite accurate: where an Applet subclass +is the single entry point for a Java Applet, an Activity should be thought of +as one of potentially several entry points to your application. The only +difference between your "main" Activity and any others you might have is that +the "main" one just happens to be the only one that expressed an interest in +the "android.intent.action.MAIN" action in your AndroidManifest..xml file.</p> + +<p>So, when designing your application, think of your application as a federation +of Activity objects. This will make your code a lot more maintainable in the long +run, and as a nice side effect also plays nicely with Android's application +history and "backstack" model.</p> + +<h2 id="themes">Extend System Themes</h2> + +<p>When it comes to the look-and-feel of the user interface, it's important to +blend in nicely. Users are jarred by applications which contrast with the user +interface they've come to expect. When designing your UIs, you should try and +avoid rolling your own as much as possible. Instead, use a Theme. You +can override or extend those parts of the theme that you need to, but at least +you're starting from the same UI base as all the other applications. For all +the details, <a href="{@docRoot}devel/ui/applying-themes.html">click here</a>.</p> + +<h2 id="flexui">Design Your UI to Work with Multiple Screen Resolutions</h2> + +<p>Different Android-powered devices will support different screen resolutions. +Some will even be able to change resolutions on the fly, such as by switching +to landscape mode. It's important to make sure your layouts and drawables +are flexible enough to display properly on a variety of device screens.</p> + +<p>Fortunately, this is very easy to do. In brief, what you must do is +provide different versions of your artwork (if you use any) for the key +resolutions, and then design your layout to accommodate various dimensions. +(For example, avoid using hard-coded positions and instead use relative +layouts.) If you do that much, the system handles the rest, and your +application looks great on any device.</p> + +<h2 id="network">Assume the Network is Slow</h2> + +<p>Android devices will come with a variety of network-connectivity options. All +will have some data-access provision, though some will be faster than others. +The lowest common denominator, however, is GPRS, the non-3G data service for +GSM networks. Even 3G-capable devices will spend lots of time on non-3G +networks, so slow networks will remain a reality for quite a long time to +come.</p> + +<p>That's why you should always code your applications to minimize network +accesses and bandwidth. You can't assume the network is fast, so you should +always plan for it to be slow. If your users happen to be on faster networks, +then that's great — their experience will only improve. You want to avoid the +inverse case though: applications that are usable some of the time, but +frustratingly slow the rest based on where the user is at any given moment are +likely to be unpopular.</p> + +<p>One potential gotcha here is that it's very easy to fall into this trap if +you're using the emulator, since the emulator uses your desktop computer's +network connection. That's almost guaranteed to be much faster than a cell +network, so you'll want to change the settings on the emulator that simulate +slower network speeds. You can do this in Eclipse, in the "Emulator Settings" +tab of your launch configuration or via a <a +href="{@docRoot}guide/developing/tools/emulator.html#netspeed">command-line +option</a> when starting the emulator.</p> + +<h2 id="keyboard">Don't Assume Touchscreen or Keyboard</h2> + +Keyboad Different Keystrokes for Different Folks</h2> +<p> +Android will support a variety of handset form-factors. That's a fancy way of +saying that some Android devices will have full "QWERTY" keyboards, while +others will have 40-key, 12-key, or even other key configurations. Similarly, +some devices will have touch-screens, but many won't. +</p><p> +When building your applications, keep that in mind. Don't make assumptions +about specific keyboard layouts -- unless, of course, you're really interested +in restricting your application so that it can only be used on those devices. +</p> + +<h2 id="network">Assume the Network is Slow</h2> +<h2 id="keyboard">Don't Assume Touchscreen or Keyboard</h2> +<h2 id="battery">Do Conserve the Device Battery</h2> +<p> +A mobile device isn't very mobile if it's constantly plugged into the +wall. Mobile devices are battery-powered, and the longer we can make that +battery last on a charge, the happier everyone is — especially the user. +Two of the biggest consumers of battery power are the processor, and the +radio; that's why it's important to write your applications to do as little +work as possible, and use the network as infrequently as possible. +</p><p> +Minimizing the amount of processor time your application uses really comes +down to <a href="performance.html">writing efficient +code</a>. To minimize the power drain from using the radio, be sure to handle +error conditions gracefully, and only fetch what you need. For example, don't +constantly retry a network operation if one failed. If it failed once, it's +likely because the user has no reception, so it's probably going to fail again +if you try right away; all you'll do is waste battery power. +</p><p> +Users are pretty smart: if your program is power-hungry, you can count on +them noticing. The only thing you can be sure of at that point is that your +program won't stay installed very long. +</p> |