M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,109 @@
page.title=Avoiding Memory Leaks
@jd:body
<p>Android applications are, at least on the T-Mobile G1, limited
to 16 MB of heap. It's both a lot of memory for a phone and yet very
little for what some developers want to achieve. Even if you do not
plan on using all of this memory, you should use as little as possible
to let other applications run without getting them killed. The more
applications Android can keep in memory, the faster it will be for the
user to switch between his apps. As part of my job, I ran into memory
leaks issues in Android applications and they are most of the time due
to the same mistake: keeping a long-lived reference to a
{@link android.content.Context Context}.</p>
<p>On Android, a <code>Context</code> is used for many operations
but mostly to load and access resources. This is why all the widgets
receive a <code>Context</code> parameter in their constructor. In a
regular Android application, you usually have two kinds of
<code>Context</code>, {@link android.app.Activity} and
{@link android.app.Application}. It's usually the first one that
the developer passes to classes and methods that need a <code>Context</code>:</p>
<pre class="prettyprint">&#64;Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
</pre>
<p>This means that views have a reference to the entire activity and
therefore to anything your activity is holding onto; usually the entire
View hierarchy and all its resources. Therefore, if you leak the <code>Context</code>
("leak" meaning you keep a reference to it thus preventing the GC from
collecting it), you leak a lot of memory. Leaking an entire activity
can be really easy if you're not careful.</p>
<p>When the screen orientation changes the system will, by default,
destroy the current activity and create a new one while preserving its
state. In doing so, Android will reload the application's UI from the
resources. Now imagine you wrote an application with a large bitmap
that you don't want to load on every rotation. The easiest way to keep
it around and not having to reload it on every rotation is to keep in a
static field:</p>
<pre class="prettyprint">private static Drawable sBackground;
&#64;Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
</pre>
<p>This code is very fast and also very wrong; it leaks the first activity
created upon the first screen orientation change. When a
{@link android.graphics.drawable.Drawable Drawable} is attached to a view, the view is set as a
{@link android.graphics.drawable.Drawable#setCallback(android.graphics.drawable.Drawable.Callback) callback}
on the drawable. In the code snippet above, this means the drawable has a
reference to the <code>TextView</code> which itself has a reference to the
activity (the <code>Context</code>) which in turns has references to
pretty much anything (depending on your code.)</p>
<p>This example is one of the simplest cases of leaking the
<code>Context</code> and you can see how we worked around it in the
<a href="http://android.git.kernel.org/?p=platform/packages/apps/Launcher.git;a=blob;f=src/com/android/launcher/LauncherModel.java;h=0ef2a806b767142b28b2ff3b37f21f4ca16c355d;hb=cupcake">Home screen's source code</a>
(look for the <code>unbindDrawables()</code> method) by setting the stored
drawables' callbacks to null when the activity is destroyed. Interestingly
enough, there are cases where you can create a chain of leaked contexts,
and they are bad. They make you run out of memory rather quickly.</p>
<p>There are two easy ways to avoid context-related memory leaks. The most
obvious one is to avoid escaping the context outside of its own scope. The
example above showed the case of a static reference but inner classes and
their implicit reference to the outer class can be equally dangerous. The
second solution is to use the <code>Application</code> context. This
context will live as long as your application is alive and does not depend
on the activities life cycle. If you plan on keeping long-lived objects
that need a context, remember the application object. You can obtain it
easily by calling
{@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
or {@link android.app.Activity#getApplication() Activity.getApplication()}.</p>
<p>In summary, to avoid context-related memory leaks, remember the following:</p>
<ul>
<li>Do not keep long-lived references to a context-activity (a reference
to an activity should have the same life cycle as the activity itself)</li>
<li>Try using the context-application instead of a context-activity</li>
<li>Avoid non-static inner classes in an activity if you don't control
their life cycle, use a static inner class and make a weak reference to
the activity inside. The solution to this issue is to use a static inner
class with a {@link java.lang.ref.WeakReference WeakReference} to the
outer class, as done in <a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/ViewRoot.java;h=9d7a124cb01ab94bf53e34f6e5e8a07f81e2423c;hb=master">ViewRoot</a>
and its W inner class for instance</li>
<li>A garbage collector is not an insurance against memory leaks</li>
</ul>

View File

@ -0,0 +1,250 @@
page.title=Backward Compatibility for Applications
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a></li>
</ol>
</div>
</div>
<p>A variety of Android-powered devices are now available to consumers from carriers
in geographies around the world. Across those devices, a range of Android
platform versions are in use, some running the latest version of the platform,
others running older versions. As a developer, you need to consider the approach
to backward compatibility that you will take in your application &mdash; do you
want to allow your application to run on all devices, or just those running the
latest software? In some cases it will be useful to employ the newer APIs on
devices that support them, while continuing to support older devices. </p>
<h3>Setting the minSdkVersion</h3>
<p>If the use of a new API is integral to the application &mdash; perhaps you
need to record video using an API introduced in Android 1.5 (API Level 3)
&mdash; you should add a <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;android:minSdkVersion&gt;</code></a>
to the application's manifest, to ensure your app won't
be installed on older devices. For example, if your application depends on an
API introduced in API Level 3, you would specify "3" as the value of the minimum
SDK version</a>:</p>
<pre> &lt;manifest&gt;
...
&lt;uses-sdk android:minSdkVersion="3" /&gt;
...
&lt;/manifest&gt;</pre>
<p>However, if you want to add a useful but non-essential feature, such as
popping up an on-screen keyboard even when a hardware keyboard is available, you
can write your program in a way that allows it to use the newer features without
failing on older devices.</p>
<h3>Using reflection</h3>
<p>Suppose there's a simple new call you want to use, like {@link
android.os.Debug#dumpHprofData(java.lang.String)
android.os.Debug.dumpHprofData(String filename)}. The {@link android.os.Debug}
class has existed since Android 1.0, but the method is new in Anroid 1.5 (API
Level 3). If you try to call it directly, your app will fail to run on devices
running Android 1.1 or earlier.</p>
<p>The simplest way to call the method is through reflection. This requires
doing a one-time lookup and caching the result in a <code>Method</code> object.
Using the method is a matter of calling <code>Method.invoke</code> and un-boxing
the result. Consider the following:</p>
<pre>public class Reflect {
private static Method mDebug_dumpHprofData;
static {
initCompatibility();
};
private static void initCompatibility() {
try {
mDebug_dumpHprofData = Debug.class.getMethod(
"dumpHprofData", new Class[] { String.class } );
/* success, this is a newer device */
} catch (NoSuchMethodException nsme) {
/* failure, must be older device */
}
}
private static void dumpHprofData(String fileName) throws IOException {
try {
mDebug_dumpHprofData.invoke(null, fileName);
} catch (InvocationTargetException ite) {
/* unpack original exception when possible */
Throwable cause = ite.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
/* unexpected checked exception; wrap and re-throw */
throw new RuntimeException(ite);
}
} catch (IllegalAccessException ie) {
System.err.println("unexpected " + ie);
}
}
public void fiddle() {
if (mDebug_dumpHprofData != null) {
/* feature is supported */
try {
dumpHprofData("/sdcard/dump.hprof");
} catch (IOException ie) {
System.err.println("dump failed!");
}
} else {
/* feature not supported, do something else */
System.out.println("dump not supported");
}
}
}</pre>
<p>This uses a static initializer to call <code>initCompatibility</code>,
which does the method lookup. If that succeeds, it uses a private
method with the same semantics as the original (arguments, return
value, checked exceptions) to do the call. The return value (if it had
one) and exception are unpacked and returned in a way that mimics the
original. The <code>fiddle</code> method demonstrates how the
application logic would choose to call the new API or do something
different based on the presence of the new method.</p>
<p>For each additional method you want to call, you would add an additional
private <code>Method</code> field, field initializer, and call wrapper to the
class.</p>
<p>This approach becomes a bit more complex when the method is declared in a
previously undefined class. It's also much slower to call
<code>Method.invoke()</code> than it is to call the method directly. These
issues can be mitigated by using a wrapper class.</p>
<h3>Using a wrapper class</h3>
<p>The idea is to create a class that wraps all of the new APIs exposed by a new
or existing class. Each method in the wrapper class just calls through to the
corresponding real method and returns the same result.</p>
<p>If the target class and method exist, you get the same behavior you would get
by calling the class directly, with a small amount of overhead from the
additional method call. If the target class or method doesn't exist, the
initialization of the wrapper class fails, and your application knows that it
should avoid using the newer calls.</p>
<p>Suppose this new class were added:</p><pre>public class NewClass {
private static int mDiv = 1;
private int mMult;
public static void setGlobalDiv(int div) {
mDiv = div;
}
public NewClass(int mult) {
mMult = mult;
}
public int doStuff(int val) {
return (val * mMult) / mDiv;
}
}</pre>
<p>We would create a wrapper class for it:</p>
<pre>class WrapNewClass {
private NewClass mInstance;
/* class initialization fails when this throws an exception */
static {
try {
Class.forName("NewClass");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/* calling here forces class initialization */
public static void checkAvailable() {}
public static void setGlobalDiv(int div) {
NewClass.setGlobalDiv(div);
}
public WrapNewClass(int mult) {
mInstance = new NewClass(mult);
}
public int doStuff(int val) {
return mInstance.doStuff(val);
}
}</pre>
<p>This has one method for each constructor and method in the original, plus a
static initializer that tests for the presence of the new class. If the new
class isn't available, initialization of <code>WrapNewClass</code> fails,
ensuring that the wrapper class can't be used inadvertently. The
<code>checkAvailable</code> method is used as a simple way to force class
initialization. We use it like this:</p>
<pre>public class MyApp {
private static boolean mNewClassAvailable;
/* establish whether the "new" class is available to us */
static {
try {
WrapNewClass.checkAvailable();
mNewClassAvailable = true;
} catch (Throwable t) {
mNewClassAvailable = false;
}
}
public void diddle() {
if (mNewClassAvailable) {
WrapNewClass.setGlobalDiv(4);
WrapNewClass wnc = new WrapNewClass(40);
System.out.println("newer API is available - " + wnc.doStuff(10));
} else {
System.out.println("newer API not available");
}
}
}</pre>
<p>If the call to <code>checkAvailable</code> succeeds, we know the new class is
part of the system. If it fails, we know the class isn't there, and adjust our
expectations accordingly. It should be noted that the call to
<code>checkAvailable</code> will fail before it even starts if the bytecode
verifier decides that it doesn't want to accept a class that has references to a
nonexistent class. The way this code is structured, the end result is the same
whether the exception comes from the verifier or from the call to
<code>Class.forName</code>.</p>
<p>When wrapping an existing class that now has new methods, you only need to
put the new methods in the wrapper class. Invoke the old methods directly. The
static initializer in <code>WrapNewClass</code> would be augmented to do a
one-time check with reflection.</p>
<h3>Testing is key</h3>
<p>You must test your application on every version of the Android framework that
is expected to support it. By definition, the behavior of your application will
be different on each. Remember the mantra: if you haven't tried it, it doesn't
work.</p>
<p>You can test for backward compatibility by running your application in an
emulator that uses an older version of the platform. The Android SDK allows you
to do this easily by creating "Android Virtual Devices" with different API
levels. Once you create the AVDs, you can test your application with old and new
versions of the system, perhaps running them side-by-side to see the
differences. More information about emulator AVDs can be found <a
href="{@docRoot}guide/developing/tools/avd.html">in the AVD documentation</a> and
from <code>emulator -help-virtual-device</code>.</p>

View File

@ -0,0 +1,69 @@
page.title=Can I Use this Intent?
@jd:body
<p>Android offers a very powerful and yet easy-to-use message type called
an <a href="{@docRoot}guide/topics/intents/intents-filters.html">intents</a>.
You can use intents to turn applications into high-level libraries and
make code modular and reusable. The Android Home screen and AnyCut
applications, for instance, use intents extensively to create shortcuts. </p>
<p>While it is nice to be able to make use of a loosely coupled
API, there is no guarantee that the intent you send will be received by
another application. This happens in particular with third-party apps, like
<a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Panoramio">Panoramio</a>
and its RADAR intent.</p>
<p>This article describes a technique you can use to find out whether the system
contains any application capable of responding to the intent you want to use.
The example below shows a helper method that queries the system package manager
to determine whether there's an app that can respond to a specified intent. Your
application can pass an intent to the method and then, for example, show or hide
user options that the user would normally use to trigger the intent. </p>
<pre class="prettyprint">/**
* Indicates whether the specified action can be used as an intent. This
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
* found, this method returns false.
*
* @param context The application's environment.
* @param action The Intent action to check for availability.
*
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List&lt;ResolveInfo&gt; list =
packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() &gt; 0;
}
</pre>
<p>Here is how you could use the helper method:</p>
<pre class="prettyprint">@Override
public boolean onPrepareOptionsMenu(Menu menu) {
final boolean scanAvailable = isIntentAvailable(this,
"com.google.zxing.client.android.SCAN");
MenuItem item;
item = menu.findItem(R.id.menu_item_add);
item.setEnabled(scanAvailable);
return super.onPrepareOptionsMenu(menu);
}
</pre>
<p>In this example, the menu is grayed out if the <em>Barcode Scanner</em>
application is not installed. </p>
<p>Another, simpler, way to do this is to catch the
<code>ActivityNotFoundException</code> when calling <code>startActivity()</code>
but it only lets you react to the problem, you cannot predict it and update the
UI accordingly to prevent the user from doing something that won't work. The
technique described here can also be used at startup time to ask the user
whether he'd like to install the missing package, you can then simply redirect
him to the Android Market by using the appropriate URI.</p>

View File

@ -0,0 +1,422 @@
page.title=Using the Contacts API
@jd:body
<p>Starting from Android 2.0 (API Level 5), the Android platform provides an
improved Contacts API for managing and integrating contacts from multiple
accounts and from other data sources. To handle overlapping data from multiple
sources, the contacts content provider aggregates similar contacts and presents
them to users as a single entity. This article describes how to use the new API
to manage contacts.</p>
<p>The new Contacts API is defined in the
{@link android.provider.ContactsContract android.provider.ContactsContract}
and related classes. The older API is still supported, although deprecated.
If you have an existing application that uses the older API,
see <a href="#legacy">Considerations for legacy apps</a>, below, for ideas
on how to support the Contacts API in your app.</p>
<p>If you'd like to look at an applied example of how to use the new Contacts
API, including how to support both the new and older API in a single app,
please see the <a
href="{@docRoot}resources/samples/BusinessCard/index.html">Business Card
sample application</a>.</p>
<h3>Data structure of Contacts</h3>
<p>In the new Contacts API, data is laid out in three primary tables:
<em>contacts</em>, <em>raw contacts</em>, and <em>data</em>, a structure that
is slightly different from that used in the older API. The new structure
allows the system to more easily store and manage information for a
specific contact from multiple contacts sources. </p>
<img style="margin: 0px auto 10px; display: block; text-align: center; width: 471px; height: 255px;" src="images/contacts-2.png" alt="" border="0">
<ul>
<li><code>Data</code> is a generic table that stores all of the data points
associated with a raw contact. Each row stores data of a specific kind &mdash;
for example name, photo, email addresses, phone numbers, and group memberships.
Each row is tagged with a MIME type to identify what type of data it can
contain, across the entire column. Columns are generic and the type of data they
contain is determined by the kind of data stored in each row. For example, if a
row's data kind is <code>Phone.CONTENT_ITEM_TYPE</code>, then the first column
stores the phone number, but if the data kind is
<code>Email.CONTENT_ITEM_TYPE</code>, then the column stores the email address.
<p>The {@link android.provider.ContactsContract.CommonDataKinds ContactsContract.CommonDataKinds}
class provides subclasses corresponding to common MIME types for contacts data.
If needed, your application or other contacts sources can define additional MIME
types for data rows. For more information about the Data table and examples of
how to use it, see {@link android.provider.ContactsContract.Data android.provider.ContactsContract.Data}.</p></li>
<li>A row in the <code>RawContacts</code> table represents the set of
<code>Data</code> and other information describing a person and associated with
a single contacts source. For example, a row might define the data associated
with a person's Google or Exchange account or Facebook friend. For more
information, see
{@link android.provider.ContactsContract.RawContacts ContactsContract.RawContacts}.</p>
<li>A row in the <code>Contacts</code> table represents an aggregate of one or
more <code>RawContacts</code> describing the same person (or entity).
<p>As mentioned above, the Contacts content provider automatically aggregates
Raw Contacts into a single Contact entry, where possible, since common data
fields (such as name or email address) are likely to be stored in each raw
contact. Since the aggregation logic maintains the entries in the Contact rows,
the entries can be read but should not be modified. See the section <a
href="#aggregation">Aggregation of contacts</a>, below, for more details,
including and information on how to
control aggregation.</li>
</ul>
<p>When displaying contacts to users, applications should typically operate on
the Contacts level, since it provides a unified, aggregated view of contacts
from various underlying sources. </p>
<h4>Example: Inserting a Phone Number</h4>
<p>To insert a phone number using the new APIs you'll need the ID of the Raw
Contact to attach the phone number to, then you'll need to create a Data
row:</p>
<pre>import android.provider.ContactsContract.CommonDataKinds.Phone;
...
ContentValues values = new ContentValues();
values.put(Phone.RAW_CONTACT_ID, rawContactId);
values.put(Phone.NUMBER, phoneNumber);
values.put(Phone.TYPE, Phone.TYPE_MOBILE);
Uri uri = getContentResolver().insert(Phone.CONTENT_URI, values);</pre>
<h3 id="aggregation">Aggregation of contacts</h3>
<p>When users sync contacts from multiple sources, several contacts might refer
to the same person or entity, but with slightly different (or overlapping) data.
For example, "Bob Parr" might be a user's co-worker and also his personal
friend, so the user might have his contact information stored in both a
corporate email account and a personal account. To provide a simplified view for
the user, the system locates such overlapping contacts and combines them into a
single, aggregate contact. </p>
<p>The system automatically aggregates contacts by default. However, if needed,
your application can control how the system handles aggregation or it can
disable aggregation altogether, as described in the sections below.</p>
<h4>Automatic aggregation</h4>
<p>When a raw contact is added or modified, the system looks for matching
(overlapping) raw contacts with which to aggregate it. It may not find any
matching raw contacts, in which case it will create an aggregate contact that
contains just the original raw contact. If it finds a single match, it creates a
new contact that contains the two raw contacts. And it may even find multiple
similar raw contacts, in which case it chooses the closest match. </p>
<p>Two raw contacts are considered to be a match if at least one of these
conditions is met:</p>
<ul>
<li>They have matching names.</li>
<li>Their names consist of the same words but in different order
(for example, "Bob Parr" and "Parr, Bob")</li>
<li>One of them has a common short name for the other (for example,
"Bob Parr" and "Robert Parr")</li>
<li>One of them has just a first or last name and it matches the other
raw contact. This rule is less reliable, so it only applies if the two
raw contacts are also sharing some other data like a phone number, an
email address or a nickname (for example, Helen ["elastigirl"] = Helen
Parr ["elastigirl"])</li>
<li>At least one of the two raw contacts is missing the name altogether
and they are sharing a phone number, an email address or a nickname (for
example, Bob Parr [incredible@android.com] = incredible@android.com).</li>
</ul>
<p>When comparing names, the system ignores upper/lower case differences
(Bob=BOB=bob) and diacritical marks (Hélène=Helene). When comparing two
phone numbers the system ignores special characters such as "*", "#",
"(", ")", and whitespace. Also if the only difference between two numbers
is that one has a country code and the other does not, then the system
considers those to be a match (except for numbers in the Japan country code).</p>
<p>Automatic aggregation is not permanent; any change of a constituent raw
contact may create a new aggregate or break up an existing one.</p>
<h4>Explicit aggregation</h4>
<p>In some cases, the system's automatic aggregation may not meet the
requirements of your application or sync adapter. There are two sets of APIs you
can use to control aggregation explicitly: <em>aggregation modes</em> allow you
to control automatic aggregation behaviors and <em>aggregation exceptions</em>
allow you to override automated aggregation entirely.
<p><strong>Aggregation modes</strong></p>
<p>You can set an aggregation mode for each raw contact individually. To do so,
add a mode constant as the value of the <code>AGGREGATION_MODE column</code> in
the <code>RawContact</code> row. The mode constants available include: </p>
<ul>
<li><code>AGGREGATION_MODE_DEFAULT</code> &mdash; normal mode, automatic
aggregation is allowed.</li>
<li><code>AGGREGATION_MODE_DISABLED</code> &mdash; automatic aggregation is not
allowed. The raw contact will not be aggregated.</li>
<li><code>AGGREGATION_MODE_SUSPENDED</code> &mdash; automatic aggregation is
deactivated. If the raw contact is already a part of an aggregated contact when
aggregation mode changes to suspended, it will remain in the aggregate, even if
it changes in such a way that it no longer matches the other raw contacts in the
aggregate.</li>
</ul>
<p><strong>Aggregation exceptions</strong></p>
<p>To keep two raw contacts unconditionally together or unconditionally apart,
you can add a row to the
{@link android.provider.ContactsContract.AggregationExceptions} table. Exceptions
defined in the table override all automatic aggregation rules. </p>
<h3>Loookup URI</h3>
<p>The new Contacts API introduces the notion of a lookup key for a contact. If
your application needs to maintain references to contacts, you should use lookup
keys instead of the traditional row ids. You can acquire a lookup key from the
contact itself, it is a column on the
{@link android.provider.ContactsContract.Contacts} table. Once you have a lookup key,
you can construct a URI in this way:</p>
<pre>Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey)</pre>
<p>and use it like you would use a traditional content URI, for example: </p>
<pre>Cursor c = getContentResolver().query(lookupUri, new String[]{Contacts.DISPLAY_NAME}, ...);
try {
c.moveToFirst();
String displayName = c.getString(0);
} finally {
c.close();
}</pre>
<p>The reason for this complication is that regular contact row IDs are
inherently volatile. Let's say your app stored a long ID of a contact. Then the
user goes and manually joins the contact with some other contact. Now there is a
single contact where there used to be two, and the stored long contact ID points
nowhere.
<p>The lookup key helps resolve the contact in this case. The key is a string
that concatenates the server-side identities of the raw contacts. Your
application can use that string to find a contact, regardless whether the raw
contact is aggregated with others or not. </p>
<p>If performance is a concern for your application, you might want to store
both the lookup and the long ID of a contact and construct a lookup URI out of
both IDs, as shown here:</p>
<pre>Uri lookupUri = getLookupUri(contactId, lookupKey)</pre>
<p>When both IDs are present in the URI, the system will try to use the long ID
first. That is a very quick query. If the contact is not found, or if the one
that is found has the wrong lookup key, the content provider will parse the
lookup key and track down the constituent raw contacts. If your app
bulk-processes contacts, you should maintain both IDs. If your app works with a
single contact per user action, you probably don't need to bother with storing
the long ID.</p>
Android itself uses lookup URIs whenever there is a need to reference a contact,
such as with shortcuts or Quick Contact, and also during editing or even viewing
a contact. The latter case is less obvious &mdash; why would a contact ID change
while we are simply viewing the contact? It could change because there might be
a sync going in the background, and the contact might get automatically
aggregated with another while being viewed.</p>
<p>In summary: whenever you need to reference a contact, we recommend that you
do so by its lookup URI.</p>
<h3 id="legacy">Considerations for legacy applications</h3>
<p>If you have an existing application that uses the older Contacts API,
you should consider upgrading it to use the new API. You have four options: </p>
<ul>
<li>Leave it as-is and rely on the Contacts compatibility mode.</li>
<li>Upgrade the app and discontinue support of pre-Android 2.0 platforms.</li>
<li>Build a new version of the app for the new API, while keeping the old version available.</li>
<li>Make the app use the right set of APIs depending on the platform where it is deployed. </li>
</ul>
<p>Let's consider these options one by one.</p>
<h4>Using compatibility mode</h4>
<p>Compatibility mode is the easiest option because you just leave the
application as is, and it should run on Android 2.0 as long as it only uses
public APIs. A couple examples of the use of non-public API include the use of
explicit table names in nested queries and the use of columns that were not
declared as public constants in the {@link android.provider.Contacts} class.
</p>
<p>Even if the application currently runs, you don't want to leave it like this
for long. The main reason is that it will only have access to contacts from one
account, namely the first Google account on the device. If the user opens other
accounts in addition to or instead of a Google account, your application will
not be able to access those contacts.</p>
<h4>Upgrading to the new API and dropping support for older platforms</h4>
<p>If your application will no longer target platforms older than
Android 2.0, you can upgrade to the new API in this way:</p>
<ul>
<li>Replace all usages of {@link android.provider.Contacts} with calls to new
API. After you are done, you should not see any deprecation warnings during
application build. The new application will be able to take full advantage of
multiple accounts and other new features of Android 2.0. </p>
<li>In the application's manifest, update (or add) the
<code>android:minSdkVersion</code> attribute to the
<code>&lt;uses-sdk&gt;</code> element. To use the new Contacts API, you should
set the value of the attribute to "5" (or higher, as appropriate). For more
information about <code>android:minSdkVersion</code>, see the documentation for
the <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
element. For more information about the value of the
<code>minSdkVersion</code>, see <a
href="{@docRoot}guide/appendix/api-levels.html">API Levels</a>.</li>
</ul>
<h4>Maintaining two applications</h4>
<p>You may decide to have two different applications: one for pre-Android 2.0
platforms and one for Android 2.0 and beyond. If so, here's what you'll need to do:</p>
<ul>
<li>Clone your existing app. </li>
<li>Change the old application: </li>
<ul>
<li>At launch time, check the version of the SDK. The version of the SDK
is available as {@link android.os.Build.VERSION#SDK android.os.Build.VERSION.SDK}.</li>
<li>If the SDK version is greater or equal to 5 (Android 2.0), show a dialog
suggesting to the user that it's time to go to Market and find a new version of
the app. You can even provide a link to the new app on Market (see <a
href="{@docRoot}guide/publishing/publishing.html#marketintent">Using Intents
to Launch Market</a>). </li>
</ul>
<li>Change the new application:</li>
<ul>
<li>Replace all usages of the older Contacts API with calls to new API.
The new application will be able to take full advantage of multiple accounts
and other new features of Android 2.0. </li>
<li>Modify that application's AndroidManifest.xml file: </li>
<ul>
<li>Give the application a new name and a new package name. Currently
Android Market does not allow you to have two applications with the same
name/package.</li>
<li>Update (or add) the <code>android:minSdkVersion</code> attribute
to the <code>&lt;uses-sdk&gt;</code> element. To use the new Contacts API,
you should set the value of the attribute to "5" (or higher, as appropriate).</li>
</ul>
</ul>
<li>Publish both apps on Market, the old app one as an upgrade and the
other as new. Make sure to explain the difference between the apps in their
descriptions.</li>
</ul>
<p>This plan has its disadvantages: </p>
<ul>
<li>The new application will not be able to read the old application's data.
Application data can only be accessed by code living in the same package. So
databases, shared preferences, and so on, will need to be populated from
scratch.</li>
<li>The upgrade process is too clunky for the user. Some users may choose
to either stay with the crippled old version or uninstall altogether.</li>
</ul>
<h4>Supporting the old and new APIs in the same application</h4>
<p>This is a bit tricky, but the result is worth the effort. You can
build a single package that will work on any platform:</p>
<p>Go through the existing application and factor out all access to
{@link android.provider.Contacts} into one class, such as ContactAccessorOldApi.
For example, if you have code like this:
<pre> protected void pickContact() {
startActivityForResult(new Intent(Intent.ACTION_PICK, People.CONTENT_URI), 0);
}</pre>
<p>it will change to:</p>
<pre> private final ContactAccessorOldApi mContactAccessor = new ContactAccessorOldApi();
void pickContact() {
startActivityForResult(mContactAccessor.getContactPickerIntent(), 0);
}</pre>
<p>The corresponding method on ContactAccessorOldApi will look like this:</p>
<pre> public Intent getContactPickerIntent() {
return new Intent(Intent.ACTION_PICK, People.CONTENT_URI);
}</pre>
<p>Once you are done, you should see deprecation warnings coming only
from ContactAccessorOldApi. </p>
<p>Create a new abstract class ContactAccessor, make sure the abstract
class has all method signatures from ContactAccessorOldApi. Make
ContactAccessorOldApi extend ContactAccessor:</p>
<pre> public abstract class ContactAccessor {
public abstract Intent getContactPickerIntent();
...
}</pre>
<p>Create a new subclass of ContactAccessor, ContactAccessorNewApi and
implement all methods using the new API:</p>
<pre> public class ContactAccessorNewApi extends ContactAccessor {
&#64;Override
public Intent getContactPickerIntent() {
return new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
}
...
}</pre>
<p>At this point, you have two implementations of the same API, one using the
old API and another using the new API. Let's plug them in. Add this code to
the ContactAccessor class:</p>
<pre> private static ContactAccessor sInstance;
public static ContactAccessor getInstance() {
if (sInstance == null) {
String className;
int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
if (sdkVersion &lt; Build.VERSION_CODES.ECLAIR) {
className = "ContactAccessorOldApi";
} else {
className = "ContactAccessorNewApi";
}
try {
Class&lt;? extends ContactAccessor&gt; clazz =
Class.forName(ContactAccessor.class.getPackage() + "." + className)
.asSubclass(ContactAccessor.class);
sInstance = clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return sInstance;
}</pre>
<p>Now replace references to ContactsAccessorOldApi with references to
ContactsAccessor:</p>
<pre> private final ContactAccessor mContactAccessor = ContactAccessor.getInstance();</pre>
<p>You are done! Now you will want to test on Android 2.0, 1.6 and 1.5.</p>
<p>We hope you like the new features and APIs we've added to Contacts in
Android 2.0, and we can't wait to see what cool things developers do with
the new APIs.</p>

View File

@ -0,0 +1,248 @@
page.title=Creating an Input Method
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}resources/articles/on-screen-inputs.html">Onscreen Input Methods</a></li>
<li><a href="{@docRoot}resources/samples/SoftKeyboard/index.html">Soft Keyboard sample</a></li>
</ol>
</div>
</div>
<p>To create an input method (IME) for entering text into text fields
and other Views, you need to extend the {@link android.inputmethodservice.InputMethodService}.
class. This class provides much of the basic implementation for an input
method, in terms of managing the state and visibility of the input method and
communicating with the currently visible activity.</p>
<p>A good starting point would be the SoftKeyboard sample code provided as part
of the SDK. You can modify the sample code to start building your own input
method.</p>
<p>An input method is packaged like any other application or service. In the
<code>AndroidManifest.xml</code> file, you declare the input method as a
service, with the appropriate intent filter and any associated meta data:</p>
<pre>&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.fastinput"&gt;
&lt;application android:label="@string/app_label"&gt;<br>
&lt;!-- Declares the input method service --&gt;
&lt;service android:name="FastInputIME"
android:label="@string/fast_input_label"
android:permission="android.permission.BIND_INPUT_METHOD"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.view.InputMethod" /&gt;
&lt;/intent-filter&gt;
&lt;meta-data android:name="android.view.im" android:resource="@xml/method" /&gt;
&lt;/service&gt;
&lt;!-- Optional activities. A good idea to have some user settings. --&gt;
&lt;activity android:name="FastInputIMESettings" android:label="@string/fast_input_settings"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"/&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;/application&gt;
&lt;/manifest&gt;</pre>
<p>If your input method allows the user to tweak some settings, you should
provide a settings activity that can be launched from the Settings application.
This is optional and you may choose to provide all user settings directly in
your IME's UI.</p>
<p>The typical life-cycle of an <code>InputMethodService</code> looks like
this:</p>
<p><img src="images/ime_003.png" style="border: medium none ; width: 374px; height: 871px;"></p>
<h3>Visual Elements</h3>
<p>There are two main visual elements for an input method—the input view and the
candidates view. You don't have to follow this style though, if one of them is
not relevant to your input method experience.</p>
<h4>Input View</h4>
<p>This is where the user can input text either in the form of keypresses,
handwriting or other gestures. When the input method is displayed for the first
time, <code>InputMethodService.onCreateInputView()</code> will be called. Create
and return the view hierarchy that you would like to display in the input method
window.</p>
<h4>Candidates View</h4>
<p>This is where potential word corrections or completions are presented to the
user for selection. Again, this may or may not be relevant to your input method
and you can return <code>null</code> from calls to
<code>InputMethodService.onCreateCandidatesView()</code>, which is the default
behavior.</p>
<h3>Designing for the different Input Types</h3>
<p>An application's text fields can have different input types specified on
them, such as free form text, numeric, URL, email address and search. When you
implement a new input method, you need to be aware of the different input types.
Input methods are not automatically switched for different input types and so
you need to support all types in your IME. However, the IME is not responsible
for validating the input sent to the application. That's the responsibility of
the application.</p>
<p>For example, the LatinIME provided with the Android platform provides
different layouts for text and phone number entry:</p>
<p><img style="margin: 0pt 10px 0pt 0pt; width: 319px; height: 198px;" src="images/ime_002.png"><img style="width: 320px; height: 199px;" src="images/ime.png"></p>
<p><code>InputMethodService.onStartInputView()</code> is called with an<code>
EditorInfo</code> object that contains details about the input type and other
attributes of the application's text field.</p><p>(<code>EditorInfo.inputType
&amp; EditorInfo.TYPE_CLASS_MASK</code>) can be one of many different values,
including:</p>
<ul>
<li><code>TYPE_CLASS_NUMBER</code></li>
<li><code>TYPE_CLASS_DATETIME</code></li>
<li><code>TYPE_CLASS_PHONE</code></li>
<li><code>TYPE_CLASS_TEXT</code></li>
</ul>
<p>See <code>android.text.InputType</code> for more details.</p>
<p><code>EditorInfo.inputType</code> can contain other masked bits that
indicate the class variation and other flags. For example,
<code>TYPE_TEXT_VARIATION_PASSWORD</code> or <code>TYPE_TEXT_VARIATION_URI</code>
or <code>TYPE_TEXT_FLAG_AUTO_COMPLETE</code>.</p>
<h4>Password fields</h4>
<p>Pay
specific attention when sending text to password fields. Make sure that
the password is not visible within your UI &mdash; neither in the input
view or the candidates view. Also, do not save the password anywhere without
explicitly informing the user.</p>
<h3>Landscape vs. portrait</h3>
<p>The UI needs to be able to scale between landscape and portrait orientations.
In non-fullscreen IME mode, leave sufficient space for the application to show
the text field and any associated context. Preferably, no more than half the
screen should be occupied by the IME. In fullscreen IME mode this is not an
issue.</p>
<h3>Sending text to the application</h3>
<p>There are two ways to send text to the application. You can either send
individual key events or you can edit the text around the cursor in the
application's text field.</p>
<p>To send a key event, you can simply construct KeyEvent objects and call
<code>InputConnection.sendKeyEvent()</code>. Here are some examples:</p>
<pre>InputConnection ic = getCurrentInputConnection();
long eventTime = SystemClock.uptimeMillis();
ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));</pre>
<p>Or use the convenience method:</p>
<pre>InputMethodService.sendDownUpKeyEvents(keyEventCode);</pre>
<p class="note"><strong>Note</strong>:
It is recommended to use the above method for certain fields such as
phone number fields because of filters that may be applied to the text
after each key press. Return key and delete key should also be sent as
raw key events for certain input types, as applications may be watching
for specific key events in order to perform an action.</p>
<p>When editing text in a text field, some of the more useful methods on
<code>android.view.inputmethod.InputConnection</code> are:</p>
<ul>
<li><code>getTextBeforeCursor()</code></li>
<li><code>getTextAfterCursor()</code></li>
<li><code>deleteSurroundingText()</code></li>
<li><code>commitText()</code></li>
</ul>
<p>For example, let's say the text "Fell" is to the left of the cursor
and you want to replace it with "Hello!":</p>
<pre>InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);</pre>
<h4>Composing text before committing</h4>
<p>If your input method does some kind of text prediction or requires multiple
steps to compose a word or glyph, you can show the progress in the text field
until the user commits the word and then you can replace the partial composition
with the completed text. The text that is being composed will be highlighted in
the text field in some fashion, such as an underline.</p>
<pre>InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
...
ic.setComposingText("Composin", 1);
...
ic.commitText("Composing ", 1);</pre>
<p><img style="width: 320px; height: 98px; margin-bottom: 10px;" src="images/ime_006.png">
<img style="width: 320px; height: 97px; margin-bottom: 10px;" src="images/ime_005.png">
<img style="width: 320px; height: 97px;" src="images/ime_004.png"></p>
<h3>Intercepting hard key events</h3>
<p>Even though the input method window doesn't have explicit focus, it receives
hard key events first and can choose to consume them or forward them along to
the application. For instance, you may want to consume the directional keys to
navigate within your UI for candidate selection during composition. Or you may
want to trap the back key to dismiss any popups originating from the input
method window. To intercept hard keys, override
<code>InputMethodService.onKeyDown()</code> and
<code>InputMethodService.onKeyUp().</code> Remember to call
<code>super.onKey</code>* if you don't want to consume a certain key
yourself.</p>
<h3>Other considerations</h3>
<ul>
<li>Provide a way for the user to easily bring up any associated settings
directly from the input method UI</li>
<li>Provide
a way for the user to switch to a different input method (multiple
input methods may be installed) directly from the input method UI.</li>
<li>Bring
up the UI quickly - preload or lazy-load any large resources so that
the user sees the input method quickly on tapping on a text field. And
cache any resources and views for subsequent invocations of the input
method.</li>
<li>On the flip side, any large memory allocations should
be released soon after the input method window is hidden so that
applications can have sufficient memory to run. Consider using a
delayed message to release resources if the input method is in a hidden
state for a few seconds.</li>
<li>Make sure that most common characters
can be entered using the input method, as users may use punctuation in
passwords or user names and they shouldn't be stuck in a situation
where they can't enter a certain character in order to gain access into
a password-locked device.</li>
</ul>
<h3>Samples</h3>
<p>For a real world example, with support for multiple input types and text
prediction, see the <a id="ccpb"
href="http://android.git.kernel.org/?p=platform/packages/inputmethods/LatinIME.
git;a=tree" title="LatinIME source code online">LatinIME source code</a>. The
Android SDK also includes a SoftKeyboard sample as well.</p>

View File

@ -0,0 +1,91 @@
page.title=Drawable Mutations
@jd:body
<p>Android's drawables are extremely useful to easily build applications. A
{@link android.graphics.drawable.Drawable Drawable} is a pluggable drawing
container that is usually associated with a View. For instance, a
{@link android.graphics.drawable.BitmapDrawable BitmapDrawable} is used to display
images, a {@link android.graphics.drawable.ShapeDrawable ShapeDrawable} to draw
shapes and gradients, and so on. You can even combine them to create complex
renderings.</p>
<p>Drawables allow you to easily customize the rendering of the widgets without
subclassing them. As a matter of fact, they are so convenient that most of the
default Android apps and widgets are built using drawables; there are about 700
drawables used in the core Android framework. Because drawables are used so
extensively throughout the system, Android optimizes them when they are loaded
from resources. For instance, every time you create a
{@link android.widget.Button Button}, a new drawable is loaded from the framework
resources (<code>android.R.drawable.btn_default</code>). This means all buttons
across all the apps use a different drawable instance as their background.
However, all these drawables share a common state, called the "constant state."
The content of this state varies according to the type of drawable you are
using, but it usually contains all the properties that can be defined by a
resource. In the case of a button, the constant state contains a bitmap image.
This way, all buttons across all applications share the same bitmap, which saves
a lot of memory.</p>
<p>The following diagram shows what entities are
created when you assign the same image resource as the background of
two different views. As you can see, two drawables are created but they
both share the same constant state, hence the same bitmap:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 307px; height: 400px;" src="images/shared_states.png" alt="" id="BLOGGER_PHOTO_ID_5331437883277472082" border="0">
<p>This state sharing feature is great to avoid wasting memory but it can cause
problems when you try to modify the properties of a drawable. Imagine an
application with a list of books. Each book has a star next to its name, totally
opaque when the user marks the book as a favorite, and translucent when the book
is not a favorite. To achieve this effect, you would probably write the
following code in your list adapter's <code>getView()</code> method:</p>
<pre>Book book = ...;
TextView listItem = ...;
listItem.setText(book.getTitle());
Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.setAlpha(255); // opaque
} else {
star.setAlpha(70); // translucent
}</pre>
<p>Unfortunately, this piece of code yields a rather strange result:
all of the drawables have the same opacity:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 267px; height: 400px;" src="images/all_drawables_changed.png" alt="" id="BLOGGER_PHOTO_ID_5331438978390342066" border="0">
<p>This
result is explained by the constant state. Even though we are getting a
new drawable instance for each list item, the constant state remains
the same and, in the case of BitmapDrawable, the opacity is part of the
constant state. Thus, changing the opacity of one drawable instance
changes the opacity of all the other instances. Even worse, working
around this issue was not easy with Android 1.0 and 1.1.</p>
<p>Android 1.5 and higher offers a very easy way to solve this issue
with the new {@link android.graphics.drawable.Drawable#mutate()} method</a>.
When you invoke this method on a drawable, the constant state of the
drawable is duplicated to allow you to change any property without
affecting other drawables. Note that bitmaps are still shared, even
after mutating a drawable. The diagram below shows what happens when
you invoke <code>mutate()</code> on a drawable:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 307px; height: 400px;" src="images/mutated_states.png" alt="" id="BLOGGER_PHOTO_ID_5331440144116345074" border="0">
<p>Let's update our previous piece of code to make use of <code>mutate()</code>:</p>
<pre>Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.mutate().setAlpha(255); // opaque
} else {
star. mutate().setAlpha(70); // translucent
}</pre>
<p>For convenience, <code>mutate()</code>
returns the drawable itself, which allows to chain method calls. It
does not however create a new drawable instance. With this new piece of
code, our application now behaves correctly:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 267px; height: 400px;" src="images/correct_drawables.png" alt="" id="BLOGGER_PHOTO_ID_5331440757515573842" border="0">

View File

@ -0,0 +1,128 @@
page.title=Faster Screen Orientation Change
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
Changes</a></li>
</ol>
</div>
</div>
<p>Android is designed to run efficiently on a wide
array of devices, with very different hardware configurations. Some
devices, like the T-Mobile G1, can change their hardware configuration
at runtime. For instance, when you open the keyboard, the screen change
from the portrait orientation to the landscape orientation.
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>Using the alternate resources framework</h2>
<p>The platform's support for loading orientation-specific
resources at run time is based on the alternate resources framework.</p>
<p>Providing orientation-specific resources is an important part of
developing your app. If you are not familiar with resource directory qualifiers
or how the platform uses them, please read
<a href="{@docRoot}guide/topics/resources/resources-i18n.html#AlternateResources">
Alternate Resources</a>.
</div>
</div>
<p>To make
Android app development easier, the Android system automatically handles
configuration change events and restarts the current activity with the new
configuration. This is the default behavior that lets you declare
resources like layouts and drawables based on the orientation, screen
size, locale, etc. </p>
<p>While this behavior is really powerful, since your application adapts
automatically to the device's configuration at runtime, it is sometimes
confusing for new Android developers, who wonder why their activity is
destroyed and recreated. </p>
<p>Facing this "issue," some developers choose to handle configuration changes
themselves which is, in general, a short-term solution that will only complicate
their lives later. On the other hand, the system's automatic resource handling
is a very efficient and easy way to adapt an application's user interface to
various devices and devices configurations. It sometimes comes at a price,
though.</p>
<p>When your application displays a lot of data, or data that is expensive to fetch,
the automatic destruction/creation of the activities can be lead to a
painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/">Photostream</a>,
a simple Flickr browsing application. After you launch the application and choose a Flickr account, the
application downloads a set of 6 photos (on a T-Mobile G1) from the
Flickr servers and displays them on screen. To improve the user
experience, the application uses slightly different layouts and drawables in
portrait and landscape modes and this is what the result looks like:</p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9l0GmPwgCzk/SZoGyJyg6-I/AAAAAAAAACU/ItuVwhegPb8/s1600-h/photostream_landscape.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="images/photostream_landscape.png" alt="" id="BLOGGER_PHOTO_ID_5303558969873198050" border="0"></a></p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9l0GmPwgCzk/SZoGx4I-QlI/AAAAAAAAACM/-GkZR5MUKhY/s1600-h/photostream_portrait.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 214px; height: 320px;" src="images/photostream_portrait.png" alt="" id="BLOGGER_PHOTO_ID_5303558965135557202" border="0"></a></p>
<p>Photostream lets Android take care of the configuration change when the
screen is rotated. However, can you imagine how painful it would be for the user
to see all the images being downloaded again? The obvious solution to this
problem is to temporarily cache the images. They could be cached on the SD card
(if there's one), in the Application object, in a static field, etc. None of
these techniques is adapted to the current situation: why should we bother
caching the images when the screen is not rotated? Fortunately for us, Android
offers a great API exactly for that purpose.</p>
<p>The Activity class has a special method called
{@link android.app.Activity#onRetainNonConfigurationInstance()}. This method
can be used to pass an arbitrary object <em>your future self</em> and Android
is smart enough to call this method only when needed. In the case of Photostream,
the application <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#226">used this method</a>
to pass the downloaded images to the future activity on orientation change.
The implementation can be summarized like so:</p>
<pre class="prettyprint">&#64;Override
public Object onRetainNonConfigurationInstance() {
final LoadedPhoto[] list = new LoadedPhoto[numberOfPhotos];
keepPhotos(list);
return list;
}
</pre>
<p>In the new activity, in <code>onCreate()</code>, all you have to do to
get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}.
In Photostream, <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#251">this method is invoked</a>
and if the returned value is not null, the grid is loaded with the list of
photos from the previous activity:</p>
<pre class="prettyprint">private void loadPhotos() {
final Object data = getLastNonConfigurationInstance();
// The activity is starting for the first time, load the photos from Flickr
if (data == null) {
mTask = new GetPhotoListTask().execute(mCurrentPage);
} else {
// The activity was destroyed/created automatically, populate the grid
// of photos with the images loaded by the previous activity
final LoadedPhoto[] photos = (LoadedPhoto[]) data;
for (LoadedPhoto photo : photos) {
addPhoto(photo);
}
}
}
</pre>
<p>Be very careful with the object you pass through
<code>onRetainNonConfigurationChange()</code>, though. If the object you
pass is for some reason tied to the Activity/Context, <a
href="http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/">you will leak</a>
all the views and resources of the activity. This means you should
never pass a View, a Drawable, an Adapter, etc. Photostream for
instance extracts the bitmaps from the drawables and pass the bitmaps
only, not the drawables. Finally, remember that
<code>onRetainNonConfigurationChange()</code> should be used only to retain
data that is expensive to load. Otherwise, keep it simple and let Android
do everything.</p>

View File

@ -0,0 +1,89 @@
page.title=Future-Proofing Your Apps
@jd:body
<p>It's important to implement your application so that it will not break as new
versions of the Android platform are loaded onto the users device. The list
below is based on our observations of five ways that we've seen bad apps fail.
You can think of these as "anti-patterns" (that is, techniques to avoid) for
Android development.</p>
<p>If your application uses any of the dubious techniques below, break out
your IDE and duct tape, spackle, and patch up the app.</p>
<p><b>Technique to Avoid, #1: Using Internal APIs</b></p>
<p>Even
though we've always strongly advised against doing so, some developers
have chosen to use unsupported or internal APIs. For instance, many
developers are using the internal brightness control and bluetooth
toggle APIs that were present in 1.0 and 1.1. A bug -- which was
fixed in Android 1.5 -- allowed apps to use those APIs without
requesting permission. As a result, apps that used those APIs broke
on 1.5. If you've used internal APIs in your apps, you need to update
your apps to stop doing so. </p>
<p><b>Technique to Avoid, #2: Directly Manipulating Settings</b></p>
<p>Strictly speaking this one isn't evil, since this is a change in
behavior that we made to Android itself. But we made it because some
developers were doing naughty things: a number of apps were changing
system settings silently without even notifying the user. For instance,
some apps turn on GPS without asking the user, and others might turn on
data roaming.</p>
<p>As a result, applications can no longer directly
manipulate the values of certain system Settings, even if they
previously had permission to do so. For instance, apps can no longer
directly turn on or off GPS. These apps won't crash, but the APIs in
question now have no effect, and do nothing. Instead, apps will need to
issue an Intent to launch the appropriate Settings configuration
screen, so that the user can change these settings manually. For
details, see the android.provider.Settings.Secure class, which you can
find in the 1.5_pre SDK documentation (and later). Note that only
Settings that were moved to the Settings.Secure class are affected.
Other, less sensitive, settings will continue to have the same behavior
as in Android 1.1.</p>
<p><b>Technique to Avoid, #3: Going Overboard with Layouts</b></p>
<p>Due to changes in the View rendering infrastructure, unreasonably deep
(more than 10 or so) or broad (more than 30 total) View hierarchies in
layouts are now likely to cause crashes. This was always a risk for
excessively complex layouts, but you can think of Android 1.5 as being
better than 1.1 at exposing this problem. Most developers won't need to
worry about this, but if your app has very complicated layouts, you'll
need to put it on a diet. You can simplify your layouts using the more
advanced layout classes like FrameLayout and TableLayout.</p>
<p><b>Technique to Avoid, #4: Bad Hardware Assumptions</b></p>
<p>Android 1.5 includes support for soft keyboards, and there will soon be many
devices that run Android but do not have physical keyboards. If your
application assumes the presence of a physical keyboard (such as if you
have created a custom View that sinks keypress events) you should make
sure it degrades gracefully on devices that only have soft keyboards.
For more information on this, keep on eye on this blog as we'll be
posting more detailed information about handling the new soft keyboards.</p>
<p><b>Technique to Avoid, #5: Incautious Rotations </b></p>
<p>Devices running Android 1.5 and later can automatically rotate the screen,
depending on how the user orients the device. Some 1.5 devices will do
this by default, and on all others it can be turned on by the user.
This can sometimes result in unpredictable behavior from applications
that do their own reorientations (whether using the accelerometer, or
something else.) This often happens when applications assume that the
screen can only rotate if the physical keyboard is exposed; if the
device lacks a physical keyboard, these apps do not expect to be
reoriented, which is a coding error. Developers should be sure that
their applications can gracefully handle being reoriented at any time.</p>
<p>Also, apps that use the accelerometer directly to reorient themselves
sometimes compete with the system doing the same thing, with odd
results. And finally, some apps that use the accelerometer to detect
things like shaking motions and that don't lock their orientation to
portrait or landscape, often end up flipping back and forth between
orientations. This can be irritating to the user. (You can lock your
app's orientation to portrait or landscape using the
<code>android:screenOrientation</code> attribute in the manifest file.)</p>

View File

@ -0,0 +1,211 @@
page.title=Gestures
@jd:body
<p>Touch screens are a great way to interact with applications on
mobile devices. With a touch screen, users can easily tap, drag, fling,
or slide to quickly perform actions in their favorite applications.
For app developers. the Android framework makes it's easy to
recognize simple actions, like a swipe, but it has been more
difficult to handle complicated gestures, sometimes requiring
developers to write a lot of code.</p>
<p>That's why we introduced a new gestures API in Android 1.6. This API, located
in the new package {@link android.gesture}, lets you store, load, draw, and
recognize gestures. This article will show you how you can use the
<code>android.gesture</code> API in your applications. Before going any further,
you should <a
href="http://code.google.com/p/apps-for-android/downloads/detail?name=
GesturesDemos.zip&amp;can=2&amp;q=#makechanges">download the source code
of the examples</a>.</p>
<h3>Creating a gestures library</h3>
<p>Android 1.6 and higher SDK platforms include a new application pre-installed
on the emulator, called Gestures Builder. You can use this application to create
a set of pre-defined gestures for your own application. It also serves as an
example of how to let the user define his own gestures in your applications. You
can find the source code of Gestures Builders in the samples directory of each
SDK platform. In our example we will use Gestures Builder to generate a set of
gestures for us (make sure to create an AVD with an SD card image to use
Gestures Builder.) The screenshot below shows what the application looks like
after adding a few gestures:</p>
<img src="images/gestures_006.png" style="width: 320px; height: 480px;">
<p>As you can see, a gesture is always associated with a name. That name is very
important because it identifies each gesture within your application. The names
do not have to be unique. Actually it can be very useful to have several
gestures with the same name to increase the precision of the recognition. Every
time you add or edit a gesture in the Gestures Builder, a file is generated on
the emulator's SD card, <code>/sdcard/gestures</code>. This file contains the
description of all the gestures, and you will need to package it inside your
application inside the resources directory, in
<code>/res/raw</code>.</p>
<h3>Loading the gestures library</h3>
<p>Now that you have a set of pre-defined gestures, you must load it inside your
application. This can be achieved in several ways but the easiest is to use the
<code>GestureLibraries</code> class:</p>
<pre class="prettyprint">mLibrary = GestureLibraries.fromRawResource(this, R.raw.spells);
if (!mLibrary.load()) {
finish();
}</pre>
<p>In this example, the gesture library is loaded from the file
<code>/res/raw/spells</code>. You can easily load libraries from other sources,
like the SD card, which is very important if you want your application to be
able to save the library; a library loaded from a raw resource is read-only and
cannot be modified. The following diagram shows the structure of a library:</p>
<img src="images/gestures_002.png" style="width: 600px; height: 512px;">
<h3>Recognizing gestures</h3>
<p>To start recognizing gestures in your application, all you have to do
is add a <code>GestureOverlayView</code> to your XML layout:</p>
<pre>&lt;android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1.0" /&gt;</pre>
<p>Notice that the <code>GestureOverlayView</code>
is not part of the usual android.widget package. Therefore, you must
use its fully qualified name. A gesture overlay acts as a simple
drawing board on which the user can draw his gestures. You can tweak
several visual properties, like the color and the width of the stroke
used to draw gestures, and register various listeners to follow what
the user is doing. The most commonly used listener is
<code>GestureOverlayView.OnGesturePerformedListener</code>,
which fires whenever a user is done drawing a gesture:</p>
<pre>GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
gestures.addOnGesturePerformedListener(this);</pre>
<p>When the listener fires, you can ask the <code>GestureLibrary</code>
to try to recognize the gesture. In return, you will get a list of
Prediction instances, each with a name - the same name you entered in
the Gestures Builder - and a score. The list is sorted by descending
scores; the higher the score, the more likely the associated gesture is
the one the user intended to draw. The following code snippet
demonstrates how to retrieve the name of the first prediction:</p>
<pre>public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList&lt;prediction&gt; predictions = mLibrary.recognize(gesture);
// We want at least one prediction
if (predictions.size() &gt; 0) {
Prediction prediction = predictions.get(0);
// We want at least some confidence in the result
if (prediction.score &gt; 1.0) {
// Show the spell
Toast.makeText(this, prediction.name, Toast.LENGTH_SHORT).show();
}
}
}</pre>
<p>In this example, the first prediction is taken into account only if it's
score is greater than 1.0. The threshold you use is entirely up to you
but know that scores lower than 1.0 are typically poor matches. And
this is all the code you need to create a simple application that can
recognize pre-defined gestures (see the source code of the project
GesturesDemo):</p>
<img src="images/gestures.png" style="width: 320px; height: 480px;">
<h3>Gestures overlay</h3>
<p>In the example above, the <code>GestureOverlayView</code> was used
as a normal view, embedded inside a <code>LinearLayout</code>.
However, as its name suggests, it can also be used as an overlay on top
of other views. This can be useful to recognize gestures in a game or
just anywhere in the UI of an application. In the second example,
called GesturesListDemo, we'll create an overlay on top of a list of
contacts. We start again in Gestures Builder to create a new set of
pre-defined gestures:</p>
<p><img src="images/gestures_005.png" style="width: 320px; height: 480px;"></p>
<p>And here is what the XML layout looks like:</p>
<pre>&lt;android.gesture.GestureOverlayView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gestureStrokeType="multiple"
android:eventsInterceptionEnabled="true"
android:orientation="vertical"&gt;
&lt;ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" /&gt;
&lt;/android.gesture.GestureOverlayView&gt;</pre>
<p>In this application, the gestures view is an overlay on top of a regular
ListView. The overlay also specifies a few properties that we did not
need before:</p>
<ul>
<li><code>gestureStrokeType</code>: indicates
whether we want to recognize gestures made of a single stroke or
multiple strokes. Since one of our gestures is the "+" symbol, we need
multiple strokes</li>
<li><code>eventsInterceptionEnabled</code>: when
set to true, this property tells the overlay to steal the events from
its children as soon as it knows the user is really drawing a gesture.
This is useful when there's a scrollable view under the overlay, to
avoid scrolling the underlying child as the user draws his gesture </li>
<li><code>orientation</code>:
indicates the scroll orientation of the views underneath. In this case
the list scrolls vertically, which means that any horizontal gestures
(like <code>action_delete</code>) can immediately be recognized as a
gesture. Gestures that start with a vertical stroke must contain at
least one horizontal component to be recognized. In other words, a
simple vertical line cannot be recognized as a gesture since it would
conflict with the list's scrolling.</li>
</ul>
<p>The code used to load and set up the gestures library and overlay is exactly
the same as before. The only difference is that we now check the name of the
predictions to know what the user intended to do:</p>
<pre>public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList&lt;Prediction&gt; predictions = mLibrary.recognize(gesture);
if (predictions.size() &gt; 0 &amp;&amp; predictions.get(0).score &gt; 1.0) {
String action = predictions.get(0).name;
if ("action_add".equals(action)) {
Toast.makeText(this, "Adding a contact", Toast.LENGTH_SHORT).show();
} else if ("action_delete".equals(action)) {
Toast.makeText(this, "Removing a contact", Toast.LENGTH_SHORT).show();
} else if ("action_refresh".equals(action)) {
Toast.makeText(this, "Reloading contacts", Toast.LENGTH_SHORT).show();
}
}
}</pre>
<p>The user is now able to draw his gestures on top of the list without
interfering with the scrolling:</p>
<img src="images/gestures_004.png" style="width: 320px; height: 480px;">
<p>The overlay even gives visual clues as to whether the gesture is considered
valid for recognition. In the case of a vertical overlay, for instance,
a single vertical stroke cannot be recognized as a gesture and is
therefore drawn with a translucent color:</p>
<img src="images/gestures_003.png" style="width: 320px; height: 480px;">
<h3>It's your turn</h3>
<p>Adding support for gestures in your application is easy and can be a valuable
addition. The gestures API does not even have to be used to recognize complex
shapes; it will work equally well to recognize simple swipes. We are very
excited by the possibilities the gestures API offers, and we're eager to see
what cool applications the community will create with it.</p>

View File

@ -0,0 +1,268 @@
page.title=Introducing GLSurfaceView
@jd:body
<p>The {@link android android.opengl.GLSurfaceView} class makes it
easier for you to use OpenGL ES rendering in your applications by:</p>
<ul>
<li>Providing the glue code to connect OpenGL ES to the {@link
android.view.View} system.</li>
<li>Providing the glue code to make OpenGL ES work with the {@link
android.app.Activity} life-cycle.</li>
<li>Making it easy to choose an appropriate frame buffer pixel format.</li>
<li>Creating and managing a separate rendering thread, to enable smooth
animation.</li>
<li>Providing easy-to-use debugging tools for tracing OpenGL ES API calls and
checking for errors.</li>
</ul>
<p>GLSurfaceView is a good base for building an application that uses OpenGL ES
for part or all of its rendering. A 2D or 3D action game would be a good
candidate, as would a 2D or 3D data visualization application such as <a
href="http://www.youtube.com/watch?v=4PRfVKzuUJ4&amp;fmt=18" title="Google Maps
StreetView">Google Maps StreetView</a>.</p>
<h3>A simple GLSurfaceView application</h3>
<p>Here's the source code to the simplest possible OpenGL ES application:</p>
<pre>package com.example.android.apis.graphics;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class ClearActivity extends Activity {
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(this);
mGLView.setRenderer(new ClearRenderer());
setContentView(mGLView);
}
&#64;Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
&#64;Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
private GLSurfaceView mGLView;
}
class ClearRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing special.
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
}
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
}</pre>
<p>This program doesn't do much: it clears the screen to black on every frame.
But it is a complete OpenGL application that correctly implements the
Android activity life-cycle. It pauses rendering when the activity is
paused, and resumes it when the activity is resumed. You could use this
application as the basis for non-interactive demonstration programs.
Just add more OpenGL calls to the <code>ClearRenderer.onDrawFrame()</code> method.
Notice that you don't even need to subclass the <code>GLSurfaceView</code> view.</p>
<p>The {@link android.opengl.GLSurfaceView.Renderer} interface has three methods:</p>
<ul>
<li>The
<code>onSurfaceCreated()</code> method is called at the start of rendering, and
whenever the OpenGL ES drawing context has to be recreated. (The
drawing context is typically lost and recreated when the activity is
paused and resumed.) <code>OnSurfaceCreated()</code> is a good place to create
long-lived OpenGL resources such as textures.</li>
<li>The <code>onSurfaceChanged()</code>
method is called when the surface changes size. It's a good place to
set your OpenGL viewport. You may also want to set your camera here, if
it's a fixed camera that doesn't move around the scene.</li>
<li>The <code>onDrawFrame()</code> method is called every frame, and is
responsible for drawing the scene. You would typically start by calling
<code>glClear</code> to clear the framebuffer, followed by other OpenGL ES calls
to draw the current scene.</li>
</ul>
<h3>How about user input?</h3>
<p>If you want an interactive application (such as a game), you will typically
subclass <code>GLSurfaceView</code>, because that's an easy way of obtaining
input events. Here's a slightly longer example showing how to do that:</p>
<pre>package com.google.android.ClearTest;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;
public class ClearActivity extends Activity {
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new ClearGLSurfaceView(this);
setContentView(mGLView);
}
&#64;Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
&#64;Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
private GLSurfaceView mGLView;
}
class ClearGLSurfaceView extends GLSurfaceView {
public ClearGLSurfaceView(Context context) {
super(context);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);
}
public boolean onTouchEvent(final MotionEvent event) {
queueEvent(new Runnable(){
public void run() {
mRenderer.setColor(event.getX() / getWidth(),
event.getY() / getHeight(), 1.0f);
}});
return true;
}
ClearRenderer mRenderer;
}
class ClearRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing special.
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
}
public void onDrawFrame(GL10 gl) {
gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
public void setColor(float r, float g, float b) {
mRed = r;
mGreen = g;
mBlue = b;
}
private float mRed;
private float mGreen;
private float mBlue;
}</pre>
<p>This application clears the screen for every frame. When you tap on the
screen, it sets the clear color based on the (x,y) coordinates of your touch
event. Note the use of <code>queueEvent()</code> in
<code>ClearGLSurfaceView.onTouchEvent()</code>. The <code>queueEvent()</code>
method is used to safely communicate between the UI thread and the rendering
thread. If you prefer, you can use some other Java cross-thread communication
technique, such as synchronized methods on the <code>Renderer</code> class
itself. However, queueing events is often the simplest way of dealing with
cross-thread communication.</p>
<h3>Other GLSurfaceView samples</h3>
<p>Tired
of just clearing the screen? You can find more interesting samples in
the API Demos sample included in the Android SDK. All the OpenGL ES samples have been
converted to use the <code>GLSurfaceView</code> view:</p>
<ul>
<li>GLSurfaceView - a spinning triangle</li>
<li>Kube - a cube puzzle demo</li>
<li>Translucent GLSurfaceView - shows how to display 3D graphics on a translucent background</li>
<li>Textured Triangle - shows how to draw a textured 3D triangle</li>
<li>Sprite Text - shows how to draw text into a texture and then composite it into a 3D scene</li>
<li>Touch Rotate - shows how to rotate a 3D object in response to user input.</li>
</ul>
<h3>Choosing a surface</h3>
<p><code>GLSurfaceView</code>
helps you choose the type of surface to render to. Different Android
devices support different types of surfaces, with no common subset.
This makes it tricky problem to choose the best available surface on
each device. </p>
<p>By default, <code>GLSurfaceView</code> tries to find a surface that's as
close as possible to a 16-bit RGB frame buffer with a 16-bit depth
buffer. Depending upon your application's needs you may want to change
this behavior. For example, the Translucent GLSurfaceView sample needs
an Alpha channel in order to render translucent data. <code>GLSurfaceView</code>
provides an overloaded <code>setEGLSurfaceChooser()</code> method to give
you control over which surface type is chosen:</p>
<dl>
<dt><code>setEGLConfigChooser(boolean needDepth)</code></dt>
<dd>Choose a config that's closest to R5G6B5 with or without a 16-bit framebuffer</dd>
<dt><code>setEGLConfigChooser(int redSize, int greenSize,int blueSize,
int alphaSize,int depthSize, int stencilSize)</code></dt>
<dd>Choose the config with the fewest number of bits per pixel that has at least
as many bits-per-channel as specified in the constructor.</dd>
<dt><code>setEGLConfigChooser(EGLConfigChooser configChooser)</code></dt>
<dd>Allow total control over choosing a configuration. You pass in your own
implementation of <code>EGLConfigChooser</code>, which gets to inspect the
device's capabilities and choose a configuration.</dd>
</dl>
<h3>Continuous rendering versus render-when-dirty</h3>
<p>Most 3D applications, such as games or simulations, are continuously
animated. But some 3D applications are more reactive: they wait passively until
the user does something, and then react to it. For those types of applications,
the default <code>GLSurfaceView</code> behavior of continuously redrawing the
screen is a waste of time. If you are developing a reactive application, you can
call <code>GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY)</code>, which
turns off the continuous animation. Then you call
<code>GLSurfaceView.requestRender()</code> whenever you want to re-render.</p>
<h3>Help With debugging</h3>
<p><code>GLSurfaceView</code> has a handy built-in feature for debugging OpenGL ES
applications: the <code>GLSurfaceView.setDebugFlags()</code> method can be used
to enable logging and/or error checking your OpenGL ES calls. Call this method
in your <code>GLSurfaceView</code>'s constructor, before calling
<code>setRenderer()</code>:</p>
<pre>public ClearGLSurfaceView(Context context) {
super(context);
// Turn on error-checking and logging
setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);
}</pre>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,157 @@
page.title=Technical Articles
@jd:body
<dl>
<dt><a href="{@docRoot}resources/articles/avoiding-memory-leaks.html">Avoiding Memory Leaks</a></dt>
<dd>Mobile devices often have limited memory, and memory leaks can cause your application to waste this valuable resource without your knowledge. This article provides tips to help you avoid common causes of memory leaks on the Android platform.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/backward-compatibility.html">Backward Compatibility</a></dt>
<dd>The Android platform strives to ensure backwards compatibility. However, sometimes you want to use new features which aren't supported on older platforms. This article discusses strategies for selectively using these features based on availability, allowing you to keep your applications portable across a wide range of devices.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/can-i-use-this-intent.html">Can I Use this Intent?</a></dt>
<dd>Android offers a very powerful and yet easy-to-use message type called an intent. You can use intents to turn applications into high-level libraries and make code modular and reusable. While it is nice to be able to make use of a loosely coupled API, there is no guarantee that the intent you send will be received by another application. This article describes a technique you can use to find out whether the system contains any application capable of responding to the intent you want to use.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/creating-input-method.html">Creating an Input Method</a></dt>
<dd>Input Method Editors (IMEs) provide the mechanism for entering text into text fields and other Views. Android devices come bundled with at least one IME, but users can install additional IMEs. This article covers the basics of developing an IME for the Android platform.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/drawable-mutations.html">Drawable Mutations</a></dt>
<dd>Drawables are pluggable drawing containers that allow applications to display graphics. This article explains some common pitfalls when trying to modify the properties of multiple Drawables.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/faster-screen-orientation-change.html">Faster Screen Orientation Change</a></dt>
<dd>When an Android device changes its orientation, the default behavior is to automatically restart the current activity with a new configuration. However, this can become a bottleneck in applications that access a large amount of external data. This article discusses how to gracefully handle this situation without resorting to manually processing configuration changes.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/future-proofing.html">Future-Proofing Your Apps</a></dt>
<dd>A collection of common sense advice to help you ensure that your applications don't break when new versions of the Android platform are released.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/gestures.html">Gestures</a></dt>
<dd>Touch screens allow users to perform gestures, such as tapping, dragging, flinging, or sliding, to perform various actions. The gestures API enables your application to recognize even complicated gestures with ease. This article explains how to integrate this API into an application.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/glsurfaceview.html">Introducing GLSurfaceView</a></dt>
<dd>This article provides an overview of GLSurfaceView, a class that makes it easy to implement 2D or 3D OpenGL rendering inside of an Android application.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/layout-tricks-reuse.html">Layout Tricks: Creating Reusable UI Components</a></dt>
<dd>Learn how to combine multiple standard UI widgets into a single high-level component, which can be reused throughout your application.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/layout-tricks-efficiency.html">Layout Tricks: Creating Efficient Layouts</a></dt>
<dd>Learn how to optimize application layouts as this article walks you through converting a LinearLayout into a RelativeLayout, and analyzes the resulting implications on performance.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/layout-tricks-stubs.html">Layout Tricks: Using ViewStubs</a></dt>
<dd>Learn about using ViewStubs inside an application's layout in order to inflate rarely used UI elements, without the performance implications which would otherwise be caused by using the <code>&lt;include&gt;</code> tag.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/layout-tricks-merge.html">Layout Tricks: Merging Layouts</a></dt>
<dd>Learn how to use the <code>&lt;merge&gt;</code> tag in your XML layouts in order to avoid unnecessary levels of hierarchy within an application's view tree.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/listview-backgrounds.html">ListView Backgrounds: An Optimization</a></dt>
<dd>ListViews are very popular widgets within the Android framework. This article describes some of the optimizations used by the ListView widget, and how to avoid some common issues that this causes when trying to use a custom background.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/live-folders.html">Live Folders</a></dt>
<dd>Live Folders allow users to display any source of data on their home screen without launching an application. This article discusses how to export an application's data in a format suitable for display inside of a live folder.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/live-wallpapers.html">Live Wallpapers</a></dt>
<dd>Live wallpapers are richer, animated, interactive backgrounds that users can display in their home screens. Learn how to create a live wallpaper and bundle it in an application that users can install on their devices.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/on-screen-inputs.html">Onscreen Input Methods</a></dt>
<dd>The Input Method Framework (IMF) allows users to take advantage of on-screen input methods, such as software keyboards. This article provides an overview of Input Method Editors (IMEs) and how applications interact with them.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/painless-threading.html">Painless Threading</a></dt>
<dd>This article discusses the threading model used by Android applications and how applications can ensure best UI performance by spawning worker threads to handle long-running operations, rather than handling them in the main thread. The article also explains the API that your application can use to interact with Android UI toolkit components running on the main thread and spawn managed worker threads.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/qsb.html">Quick Search Box</a></dt>
<dd>Quick Search Box (QSB) is a powerful, system-wide search framework. QSB makes it possible for users to quickly and easily find what they're looking for, both on their devices and on the web. This article discusses how to work with the QSB framework to add new search results for an installed application.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/touch-mode.html">Touch Mode</a></dt>
<dd>This article explains the touch mode, one of the most important principles of Android's UI toolkit. Whenever a user interacts with a device's touch screen, the system enters touch mode. While simple in concept, there are important implications touch mode that are often overlooked.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/track-mem.html">Tracking Memory Allocations</a></dt>
<dd>This article discusses how to use the Allocation Tracker tool to observe memory allocations and avoid performance problems that would otherwise be caused by ignoring the effect of Dalvik's garbage collector.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/ui-1.5.html">UI Framework Changes in Android 1.5</a></dt>
<dd>Explore the UI changes that were introduced in Android 1.5, compared with the UI provided in Android 1.0 and 1.1.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/ui-1.6.html">UI Framework Changes in Android 1.6</a></dt>
<dd>Explore the UI changes that were introduced in Android 1.6, compared with the UI provided in Android 1.5. In particular, this article discusses changes to RelativeLayouts and click listeners.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/timed-ui-updates.html">Updating the UI from a Timer</a></dt>
<dd>Learn about how to use Handlers as a more efficient replacement for java.util.Timer on the Android platform.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/tts.html">Using Text-to-Speech</a></dt>
<dd>The text-to-speech API lets your application "speak" to users, in any of several languages. This article provides an overview of the TTS API and how you use to add speech capabilities to your application.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/tts.html">Using the Contacts API</a></dt>
<dd>This article discusses the improved Contacts API introduced in Android 2.0 and how to use it to manage and integrate contacts from multiple accounts and data sources. The article also discusses techniques for using the new API on devices that support it, while maintaining backward compatibility with the old API on other devices. </dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/using-webviews.html">Using WebViews</a></dt>
<dd>WebViews allow an application to dynamically display HTML and execute JavaScript, without relinquishing control to a separate browser application. This article introduces the WebView classes and provides a sample application that demonstrates its use.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/wikinotes-linkify.html">WikiNotes: Linkify your Text!</a></dt>
<dd>This article introduces WikiNotes for Android, part of the Apps for Android project. It covers the use of Linkify to turn ordinary text views into richer, link-oriented content that causes Android intents to fire when a link is selected.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/wikinotes-intents.html">WikiNotes: Routing Intents</a></dt>
<dd>This article illustrates how an application, in this case the WikiNotes sample app, can use intents to route various types of linked text to the application that handles that type of data. For example, an app can use intents to route a linked telephone number to a dialer app and a web URL to a browser.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/window-bg-speed.html">Window Backgrounds & UI Speed</a></dt>
<dd>Some Android applications need to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both of these techniques rely on a single feature, the window's background drawable.</dd>
</dl>
<dl>
<dt><a href="{@docRoot}resources/articles/zipalign.html">Zipalign: an Easy Optimization</a></dt>
<dd>The Android SDK includes a tool called zipalign that optimizes the way an application is packaged. Running zipalign against your application enables Android to interact with it more efficiently at run time and thus has the potential to make it and the overall system run faster. This article provides a high-level overview of the zipalign tool and its use.</dd>
</dl>

View File

@ -0,0 +1,177 @@
page.title=Layout Tricks: Creating Efficient Layouts
@jd:body
<p>The Android UI toolkit offers several layout managers that are
rather easy to use and, most of the time, you only need the basic
features of these layout managers to implement a user interface.</p>
<p>Sticking to the basic features is unfortunately not the most efficient
way to create user interfaces. A common example is the abuse of
{@link android.widget.LinearLayout}, which leads to a proliferation of
views in the view hierarchy. Every view &mdash; or worse, every layout
manager &mdash; that you add to your application comes at a cost:
initialization, layout and drawing become slower. The layout pass can be
especially expensive when you nest several <code>LinearLayout</code>
that use the {@link android.R.attr#layout_weight weight}
parameter, which requires the child to be measured twice.</p>
<p>Let's consider a very simple and common example of a layout: a list item
with an icon on the left, a title at the top and an optional description
underneath the title. Here is what such an item looks like:</p>
<div style="text-align: center;"><img src="images/relativelayout_1.png" alt="Simple list item"></div>
<p>To clearly understand how the views, one {@link android.widget.ImageView} and
two {@link android.widget.TextView}, are positioned with respect to each other,
here is the wireframe of the layout as captured by <a
href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">HierarchyViewer</a
>:</p>
<div style="text-align: center;"><img src="images/relativelayout_wire_1.png" alt="Wireframe of the simple list item"></div>
<p>Implementing this layout is straightforward with <code>LinearLayout</code>.
The item itself is a horizontal <code>LinearLayout</code> with an
<code>ImageView</code> and a vertical <code>LinearLayout</code>, which contains
the two <code>TextView</code>. Here's the source code of this layout:</p>
<pre class="prettyprint">&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"&gt;
&lt;ImageView
android:id="&#64;+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:src="&#64;drawable/icon" /&gt;
&lt;LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent"&gt;
&lt;TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="My Application" /&gt;
&lt;TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application that shows how to use RelativeLayout" /&gt;
&lt;/LinearLayout&gt;
&lt;/LinearLayout&gt;</pre>
<p>This layout works but can be wasteful if you instantiate it for every list
item of a {@link android.widget.ListView}. The same layout can be rewritten
using a single {@link android.widget.RelativeLayout}, thus saving one view, and
even better one level in view hierarchy, per list item. The implementation of
the layout with a <code>RelativeLayout</code> remains simple:</p>
<pre class="prettyprint">&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"&gt;
&lt;ImageView
android:id="&#64;+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="6dip"
android:src="&#64;drawable/icon" /&gt;
&lt;TextView
android:id="&#64;+id/secondLine"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="&#64;id/icon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application that shows how to use RelativeLayout" /&gt;
&lt;TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="&#64;id/icon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="&#64;id/secondLine"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_vertical"
android:text="My Application" /&gt;
&lt;/RelativeLayout&gt;</pre>
<p>This new implementation behaves exactly the same way as the previous
implementation, except in one case. The list item we want to display has two
lines of text: the title and an <em>optional</em> description. When a
description is not available for a given list item, the application would simply
set the visibility of the second <code>TextView</code> to
{@link android.view.View#GONE}. This works perfectly with the <code>LinearLayout</code>
implementation but not with the <code>RelativeLayout</code> version:</p>
<div style="text-align: center;"><img src="images/relativelayout_2.png" alt="RelativeLayout and description GONE"></div>
<div style="text-align: center;"><img src="images/relativelayout_wire_2.png" alt="RelativeLayout and description GONE"></div>
<p>In a <code>RelativeLayout</code>, views are aligned with their parent, with the
<code>RelativeLayout</code> itself, or with other views. For instance, we declared that
the description is aligned with the bottom of the <code>RelativeLayout</code> and
that the title is positioned above the description and anchored to the
parent's top. With the description GONE, RelativeLayout doesn't know
where to position the title's bottom edge. To solve this problem, you
can use a very special layout parameter called
{@link android.R.attr#layout_alignWithParentIfMissing}.
</p>
<p>This boolean parameter simply tells RelativeLayout to use its own edges as
anchors when a constraint target is missing. For instance, if you position a
view to the right of a GONE view and set <code>alignWithParentIfMissing</code>
to <code>true</code>, <code>RelativeLayout</code> will instead anchor the view
to its left edge. In our case, using <code>alignWithParentIfMissing</code> will
cause <code>RelativeLayout</code> to align the title's bottom with its own
bottom. The result is the following:</p>
<div style="text-align: center;"><img src="images/relativelayout_3.png" alt="RelativeLayout, description GONE and alignWithParentIfMissing"></div>
<div style="text-align: center;"><img src="images/relativelayout_wire_3.png" alt="RelativeLayout, description GONE and alignWithParentIfMissing"></div>
<p>The
behavior of our layout is now perfect, even when the description is
GONE. Even better, the hierarchy is simpler and because we are not
using LinearLayout's weights it's also more efficient. The difference
between the two implementations becomes obvious when comparing the view
hierarchies in HierarchyViewer:</p>
<div style="text-align: center;"><img src="images/layouts_comparison_small.png" alt="LinearLayout vs RelativeLayout"></div>
<p>Again, the difference will be much more important when you use such a layout
for every item in a ListView for instance. Hopefully this simple
example showed you that getting to know your layouts is the best way to
learn how to optimize your UI.</p>

View File

@ -0,0 +1,200 @@
page.title=Layout Tricks: Merging Layouts
@jd:body
<p>The articles showed you how to use the <code>&lt;include /&gt;</code> tag in XML layouts, to
reuse and share your layout code. This article explains the <code>&lt;merge /&gt;</code> tag and how
it complements the <code>&lt;include /&gt;</code> tag.</p>
<p>The <code>&lt;merge /&gt;</code> tag was created for the purpose of
optimizing Android layouts by reducing the number of levels in view trees. It's
easier to understand the problem this tag solves by looking at an example. The
following XML layout declares a layout that shows an image with its title on top
of it. The structure is fairly simple; a {@link android.widget.FrameLayout} is
used to stack a {@link android.widget.TextView} on top of an
{@link android.widget.ImageView}:</p>
<pre class="prettyprint">&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"&gt;
&lt;ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="&#64;drawable/golden_gate" /&gt;
&lt;TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" /&gt;
&lt;/FrameLayout&gt;</pre>
<p>This layout renders nicely and nothing seems wrong with it:</p>
<div style="text-align: center;"><img src="images/merge1.jpg" alt="A FrameLayout is used to overlay a title on top of an image"></div>
<p>Things get more interesting when you inspect the result with <a
href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">HierarchyViewer</a>.
If you look closely at the resulting tree, you will notice that the
<code>FrameLayout</code> defined in our XML file (highlighted in blue below) is
the sole child of another <code>FrameLayout</code>:</p>
<div style="text-align: center;"><img src="images/merge2.png" alt="A layout with only one child of same dimensions can be removed"></div>
<p>Since our <code>FrameLayout</code> has the same dimension as its parent, by
the virtue of using the <code>fill_parent</code> constraints, and does not
define any background, extra padding or a gravity, it is <em>totally
useless</em>. We only made the UI more complex for no good reason. But how could
we get rid of this <code>FrameLayout</code>? After all, XML documents require a
root tag and tags in XML layouts always represent view instances.</p>
<p>That's where the <code>&lt;merge /&gt;</code> tag comes in handy. When the
{@link android.view.LayoutInflater} encounters this tag, it skips it and adds
the <code>&lt;merge /&gt;</code> children to the <code>&lt;merge /&gt;</code>
parent. Confused? Let's rewrite our previous XML layout by replacing the
<code>FrameLayout</code> with <code>&lt;merge /&gt;</code>:</p>
<pre class="prettyprint">&lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&gt;
&lt;ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="&#64;drawable/golden_gate" /&gt;
&lt;TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" /&gt;
&lt;/merge&gt;</pre>
<p>With this new version, both the <code>TextView</code> and the
<code>ImageView</code> will be added directly to the top-level
<code>FrameLayout</code>. The result will be visually the same but the view
hierarchy is simpler:</p>
<div style="text-align: center;"><img src="images/merge3.png" alt="Optimized view hierarchy using the merge tag"></div>
<p>Obviously, using <code>&lt;merge /&gt;</code> works in this case because the
parent of an activity's content view is always a <code>FrameLayout</code>. You
could not apply this trick if your layout was using a <code>LinearLayout</code>
as its root tag for instance. The <code>&lt;merge /&gt;</code> can be useful in
other situations though. For instance, it works perfectly when combined with the
<code>&lt;include /&gt;</code> tag. You can also use <code>&lt;merge
/&gt;</code> when you create a custom composite view. Let's see how we can use
this tag to create a new view called <code>OkCancelBar</code> which simply shows
two buttons with customizable labels. You can also <a
href="http://progx.org/users/Gfx/android/MergeLayout.zip">download the complete
source code of this example</a>. Here is the XML used to display this custom
view on top of an image:</p>
<pre class="prettyprint">&lt;merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"&gt;
&lt;ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="&#64;drawable/golden_gate" /&gt;
&lt;com.example.android.merge.OkCancelBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="8dip"
android:gravity="center_horizontal"
android:background="#AA000000"
okCancelBar:okLabel="Save"
okCancelBar:cancelLabel="Don't save" /&gt;
&lt;/merge&gt;</pre>
<p>This new layout produces the following result on a device:</p>
<div style="text-align: center;"><img src="images/merge4.jpg" alt="Creating a custom view with the merge tag"></div>
<p>The source code of <code>OkCancelBar</code> is very simple because the two
buttons are defined in an external XML file, loaded using a
<code>LayoutInflate</code>. As you can see in the following snippet, the XML
layout <code>R.layout.okcancelbar</code> is inflated with the
<code>OkCancelBar</code> as the parent:</p>
<pre class="prettyprint">public class OkCancelBar extends LinearLayout {
public OkCancelBar(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER);
setWeightSum(1.0f);
LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
String text = array.getString(R.styleable.OkCancelBar_okLabel);
if (text == null) text = "Ok";
((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
text = array.getString(R.styleable.OkCancelBar_cancelLabel);
if (text == null) text = "Cancel";
((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
array.recycle();
}
}</pre>
<p>The two buttons are defined in the following XML layout. As you can see, we
use the <code>&lt;merge /&gt;</code> tag to add the two buttons directly to the
<code>OkCancelBar</code>. Each button is included from the same external XML
layout file to make them easier to maintain; we simply override their id:</p>
<pre class="prettyprint">&lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&gt;
&lt;include
layout="&#64;layout/okcancelbar_button"
android:id="&#64;+id/okcancelbar_ok" /&gt;
&lt;include
layout="&#64;layout/okcancelbar_button"
android:id="&#64;+id/okcancelbar_cancel" /&gt;
&lt;/merge&gt;</pre>
<p>We have created a flexible and easy to maintain custom view that generates
an efficient view hierarchy:</p>
<div style="text-align: center;"><img src="images/merge5.png" alt="The resulting hierarchy is simple and efficient"></div>
<p>The <code>&lt;merge /&gt;</code> tag is extremely useful and can do wonders
in your code. However, it suffers from a couple of limitations:</p>
<ul>
<li><code>&lt;merge /&gt;</code> can only be used as the root tag of an XML layout</li>
<li>When inflating a layout starting with a <code>&lt;merge /&gt;</code>, you <strong>must</strong>
specify a parent <code>ViewGroup</code> and you must set <code>attachToRoot</code> to
<code>true</code> (see the documentation for
{@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} method)</li>
</ul>

View File

@ -0,0 +1,79 @@
page.title=Layout Tricks: Creating Reusable UI Components
@jd:body
<p>The Android platform offers a wide variety of UI <em>widgets</em>, small
visual construction blocks that you can glue together to present users with
complex and useful interfaces. However applications often need higher-level
visual <em>components</em>. To meet that need, and to do so efficiently, you can
combine multiple standard widgets into a single, reusable component. </p>
<p>For example, you could create a reusable component that contains a progress
bar and a cancel button, a panel containing two buttons (positive and negative
actions), a panel with an icon, a title and a description, and so on. You can
create UI components easily by writing a custom <code>View</code>, but you can
do it even more easily using only XML.</p>
<p>In Android XML layout files, each tag is mapped to an actual class instance
(the class is always a subclass of {@link android.view.View} The UI toolkit lets
you also use three special tags that are not mapped to a <code>View</code>
instance: <code>&lt;requestFocus /&gt;</code>, <code>&lt;merge /&gt;</code> and
<code>&lt;include /&gt;</code>. This article shows how to use <code>&lt;include
/&gt;</code> to create pure XML visual components. For information about how to
use <code>&lt;merge /&gt;</code>, which can be particularly powerful when
combined with <code>&lt;include /&gt;</code>see the <a
href="{@docRoot}resources/articles/layout-tricks-merge.html">Merging Layouts</a>
article. </p>
<p>The <code>&lt;include /&gt;</code> element does exactly what its name
suggests; it includes another XML layout. Using this tag is straightforward as
shown in the following example, taken straight from <a
href="http://android.git.kernel.org/?p=platform/packages/apps/Launcher.git;a=
tree;h=refs/heads/master;hb=master">the source code of the Home application</a>
that ships with Android:</p>
<pre class="prettyprint">&lt;com.android.launcher.Workspace
android:id="&#64;+id/workspace"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
launcher:defaultScreen="1"&gt;
&lt;include android:id="&#64;+id/cell1" layout="@layout/workspace_screen" /&gt;
&lt;include android:id="&#64;+id/cell2" layout="@layout/workspace_screen" /&gt;
&lt;include android:id="&#64;+id/cell3" layout="@layout/workspace_screen" /&gt;
&lt;/com.android.launcher.Workspace&gt;</pre>
<p>In the <code>&lt;include /&gt;</code> only the <code>layout</code> attribute
is required. This attribute, without the <code>android</code> namespace prefix,
is a reference to the layout file you wish to include. In this example, the same
layout is included three times in a row. This tag also lets you override a few
attributes of the included layout. The above example shows that you can use
<code>android:id</code> to specify the id of the root view of the included
layout; it will also override the id of the included layout if one is defined.
Similarly, you can override all the layout parameters. This means that any
<code>android:layout_*</code> attribute can be used with the <code>&lt;include
/&gt;</code> tag. Here is an example in
which the same layout is included twice, but only the first one overrides the layout properties:</p>
<pre>
&lt;!-- override the layout height and width --&gt;
&lt;include layout="@layout/image_holder"
android:layout_height="fill_parent"
android:layout_width="fill_parent" /&gt;
&lt;!-- do not override layout dimensions; inherit them from image_holder --&gt;
&lt;include layout="@layout/image_holder" /&gt;
</pre>
<p class="caution"><strong>Caution:</strong> If you want to override the layout dimensions,
you must override both <code>android:layout_height</code> and
<code>android:layout_width</code>&mdash;you cannot override only the height or only the width.
If you override only one, it will not take effect. (Other layout properties, such as weight,
are still inherited from the source layout.)</p>
<p>This tag is particularly useful when you need to customize only part of your
UI depending on the device's configuration. For instance, the main layout of
your activity can be placed in the <code>layout/</code> directory and can
include another layout which exists in two flavors, in <code>layout-land/</code>
and <code>layout-port/</code>. This allows you to share most of the UI in
portrait and landscape.</p>

View File

@ -0,0 +1,84 @@
page.title=Layout Tricks: Using ViewStubs
@jd:body
<p>Sharing and reusing UI components is very easy with Android, thanks to the <a
href="layout-tricks-reuse.html">&lt;include /&gt;</a> tag. Sometimes it's so
easy to create complex UI constructs that your UI ends up with a large number of
views, some of which are rarely used. Thankfully, Android offers a very special
widget called {@link android.view.ViewStub}, which brings you all the benefits
of the <code>&lt;include /&gt;</code> without polluting your user interface with
rarely used views.</p>
<p>A <code>ViewStub</code> is a dumb and lightweight view. It has no dimension,
it does not draw anything and does not participate in the layout in any way.
This means that a <code>ViewStub</code> is very cheap to inflate and very cheap
to keep in a view hierarchy. A <code>ViewStub</code> can be best described as a
<em>lazy include</em>. The layout referenced by a <code>ViewStub</code> is
inflated and added to the user interface only when you decide so.</p>
<p>The following screenshot comes from the <a
href="http://code.google.com/p/shelves">Shelves</a> application. The main purpose of
the activity shown in the screenshot is to present the user with a browsable
list of books:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center;" src="images/viewstub1.png" alt="" id="BLOGGER_PHOTO_ID_5314039375336055346" border="0">
<p>The same activity is also used when the user adds or imports new books.
During such an operation, Shelves shows extra bits of user interface.
The screenshot below shows the progress bar and cancel button that
appear at the bottom of the screen during an import:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center;" src="images/viewstub2.png" alt="" id="BLOGGER_PHOTO_ID_5314039800002559378" border="0">
<p>Because importing books is not a common operation, at least when compared to
browsing the list of books, the import panel is originally represented
by a <code>ViewStub</code>:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center;" src="images/viewstub3.png" alt="" id="BLOGGER_PHOTO_ID_5314040334008167378" border="0">
<p>When the user initiates the import process, the <code>ViewStub</code> is
inflated and replaced by the content of the layout file it references:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center;" src="images/viewstub4.png" alt="" id="BLOGGER_PHOTO_ID_5314040638747834450" border="0">
<p>To use a <code>ViewStub</code>, all you need is to specify an
<code>android:id</code> attribute, to later inflate the stub, and an
<code>android:layout</code> attribute, to reference what layout file
to include and inflate. A stub lets you use a third attribute,
<code>android:inflatedId</code>, which can be used to override the
<code>id</code> of the root of the included file. Finally, the layout
parameters specified on the stub will be applied to the roof of the
included layout. Here is an example:</p>
<pre class="prettyprint">&lt;ViewStub
android:id="&#64;+id/stub_import"
android:inflatedId="&#64;+id/panel_import"
android:layout="&#64;layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" /&gt;</pre>
<p>When you are ready to inflate the stub, simply invoke the
{@link android.view.ViewStub#inflate()} method. You can also simply change the
visibility of the stub to {@link android.view.View#VISIBLE} or
{@link android.view.View#INVISIBLE} and the stub will inflate. Note however that the
<code>inflate()</code> method has the benefit of returning the root
<code>View</code> of the inflate layout:</p>
<pre class="prettyprint">((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();</pre>
<p>It is very important to remember that after the stub is inflated, the stub is
<em>removed</em> from the view hierarchy. As such, it is unnecessary to keep a
long-lived reference, for instance in an class instance field, to a
<code>ViewStub</code>.</p>
<p>A <code>ViewStub</code> is a great compromise between ease of programming and
efficiency. Instead of inflating views manually and adding them at runtime to
your view hierarchy, simply use a <code>ViewStub</code>. It's cheap and easy.
The only drawback of <code>ViewStub</code> is that it currently does
<em>not</em> support the <a href="layout-tricks-merge.html">&lt;merge /&gt;
tag</a>.</p>

View File

@ -0,0 +1,86 @@
page.title=ListView Backgrounds: An Optimization
@jd:body
<p>{@link android.widget.ListView} is one of Android's most widely used widgets.
It is rather easy to use, very flexible, and incredibly powerful.
<code>ListView</code> can also be difficult to understand at times.</p>
<p>One of the most common issues with <code>ListView</code> happens when you try
to use a custom background. By default, like many Android widgets,
<code>ListView</code> has a transparent background which means that you can see
through the default window's background, a very dark gray
(<code>#FF191919</code> with the current <code>dark</code> theme.) Additionally,
<code>ListView</code> enables the <em>fading edges</em> by default, as you can
see at the top of the following screenshot &mdash; the first text item gradually
fades to black. This technique is used throughout the system to indicate that
the container can be scrolled.</p>
<div style="text-align: center;"><img src="images/list_fade_1.png" alt="Android's default ListView"></div>
<p>The fade effect is implemented using a combination of
{@link android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int) Canvas.saveLayerAlpha()}
and the {@link android.graphics.PorterDuff.Mode#DST_OUT Porter-Duff Destination Out blending mode}. </p>
<p>Unfortunately, things start to get ugly when you try to use a custom
background on the <code>ListView</code> or when you change the window's
background. The following two screenshots show what happens in an application
when you change the window's background. The left image shows what the list
looks like by default and the right image shows what the list looks like during
a scroll initiated with a touch gesture:</p>
<div style="text-align: center;">
<img style="margin-right: 12px;" src="images/list_fade_2.png" alt="Dark fade">
<img src="images/list_fade_3.png" alt="Dark list"></div>
<p>This rendering issue is caused by an optimization of the Android framework
enabled by default on all instances of <code>ListView</code>. I mentioned
earlier that the fade effect is implemented using a Porter-Duff blending mode.
This implementation works really well but is unfortunately very costly and can
bring down drawing performance by quite a bit as it requires to capture a
portion of the rendering in an offscreen bitmap and then requires extra blending
(which implies readbacks from memory.)</p>
<p>Since <code>ListView</code> is most of the time displayed on a solid
background, there is no reason to go down that expensive route. That's why we
introduced an optimization called the "cache color hint." The cache color hint
is an RGB color set by default to the window's background color, that is #191919
in Android's dark theme. When this hint is set, <code>ListView</code> (actually,
its base class <code>View</code>) knows it will draw on a solid background and
therefore replaces th expensive <code>saveLayerAlpha()/Porter-Duff</code>
rendering with a simple gradient. This gradient goes from fully transparent to
the cache color hint value and this is exactly what you see on the image above,
with the dark gradient at the bottom of the list. However, this still does not
explain why the entire list turns black during a scroll.</p>
<p>As mentioned before, <code>ListView</code> has a transparent/translucent
background by default, and so all default widgets in the Android UI toolkit.
This implies that when <code>ListView</code> redraws its children, it has to
blend the children with the window's background. Once again, this requires
costly readbacks from memory that are particularly painful during a scroll or a
fling when drawing happens dozen of times per second. </p>
<p>To improve drawing performance during scrolling operations, the Android
framework reuses the cache color hint. When this hint is set, the framework
copies each child of the list in a <code>Bitmap</code> filled with the hint
value (assuming that another optimization, called <em>scrolling cache</em>, is
not turned off). <code>ListView</code> then blits these bitmaps directly on
screen and because these bitmaps are known to be opaque, no blending is
required. Also, since the default cache color hint is <code>#191919</code>, you
get a dark background behind each item during a scroll.</p>
<p>To fix this issue, all you have to do is either disable the cache color hint
optimization, if you use a non-solid color background, or set the hint to the
appropriate solid color value. You can do this from code (see
{@link android.widget.AbsListView#setCacheColorHint(int)}) or preferably from
XML, by using the <code>android:cacheColorHint</code> attribute. To disable the
optimization, simply use the transparent color <code>#00000000</code>. The
following screenshot shows a list with
<code>android:cacheColorHint="#00000000"</code> set in the XML layout file:</p>
<div style="text-align: center;"><img src="images/list_fade_4.png" alt="Fade on a custom background"></div>
<p>As you can see, the fade works perfectly against the custom wooden
background. The cache color hint feature is interesting because it
shows how optimizations can make your life more difficult in
some situations. In this particular case, however, the benefit of the
default behavior outweighs the added complexity..</p>

View File

@ -0,0 +1,168 @@
page.title=Live Folders
@jd:body
<p>Live folders, introduced in Android 1.5 (API Level 3), let you display any source of data
on the Home screen without forcing the user to launch an application. A live
folder is simply a real-time view of a {@link android.content.ContentProvider}.
As such, a live folder can be used to display all of the user's contacts or
bookmarks, email, playlists, an RSS feed, and so on. The possibilities are
endless! </p>
<p>The platform includes several standard folders for displaying contacts. For
instance, the screenshot below shows the content of the live folders that
displays all contacts with a phone number:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 267px; height: 400px;" src="images/contacts.png" alt="" id="BLOGGER_PHOTO_ID_5323287788220889218" border="0">
<p>If a contacts sync happens in the background while the user is browsing this live
folder, the user will see the change happen in real-time. Live folders are not
only useful, but they are also easy to add to to your application and data.
This articles shows how to add a live folder to an example application called
Shelves. To better understand how live folders work, you can <a
href="http://code.google.com/p/shelves">download the source code of the
application</a> and modify it by following the instructions below.</p>
<p>To give the user the option to create a new live folder for an application,
you first need to create a new activity with an intent filter whose action is
<code>android.intent.action.CREATE_LIVE_FOLDER</code>. To do so, simply open
<code>AndroidManifest.xml</code> and add something similar to this:</p>
<pre>&lt;activity
android:name=".activity.BookShelfLiveFolder"
android:label="BookShelf"&gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.CREATE_LIVE_FOLDER" /&gt;
&lt;category android:name="android.intent.category.DEFAULT" /&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;</pre>
<p>The label and icon of this activity are what the user will see on the Home
screen when choosing a live folder to create:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 267px; height: 400px;" src="images/device_002.png" alt="" id="BLOGGER_PHOTO_ID_5323289217773103922" border="0">
<p>Since you just need an intent filter, it is possible, and sometimes advised,
to reuse an existing activity. In the case of Shelves, we will create a new
activity, <code>org.curiouscreature.android.shelves.activity.BookShelfLiveFolder</code>.
The role of this activity is to send an <code>Intent</code> result to Home
containing the description of the live folder: its name, icon, display mode and
content URI. The content URI is very important as it describes what
<code>ContentProvider</code> will be used to populate the live folder. The code
of the activity is very simple as you can see here:</p>
<pre>public class BookShelfLiveFolder extends Activity {
public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books");
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
final String action = intent.getAction();
if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI,
"Books", R.drawable.ic_live_folder));
} else {
setResult(RESULT_CANCELED);
}
finish();
}
private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) {
final Intent intent = new Intent();
intent.setData(uri);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
Intent.ShortcutIconResource.fromContext(context, icon));
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);
return intent;
}
}</pre>
<p>This activity, when invoked with the<code>ACTION_CREATE_LIVE_FOLDER</code>
intent, returns an intent with a URI,
<code>content://shelves/live_folders/books</code>, and three extras to describe
the live folder. There are other extras and constants you can use and you should
refer to the documentation of <code>android.provider.LiveFolders</code> for more
details. When Home receives this intent, a new live folder is created on the
user's desktop, with the name and icon you provided. Then, when the user clicks
on the live folder to open it, Home queries the content provider referenced by
the provided URI.</p>
<p>Live folders' content providers must obey specific naming rules. The
<code>Cursor</code> returned by the <code>query()</code> method must have at
least two columns named <code>LiveFolders._ID</code> and
<code>LiveFolders.NAME</code>. The first one is the unique identifier of each
item in the live folder and the second one is the name of the item. There are
other column names you can use to specify an icon, a description, the intent to
associate with the item (fired when the user clicks that item), etc. Again,
refer to the documentation of <code>android.provider.LiveFolders</code> for more
details.</p><p>In our example, all we need to do is modify the existing provider
in Shelves called
<code>org.curiouscreature.android.shelves.provider.BooksProvider</code>. First,
we need to modify the <code>URI_MATCHER</code> to recognize our
<code>content://shelves/live_folders/books</code> content URI:</p>
<pre>private static final int LIVE_FOLDER_BOOKS = 4;
// ...
URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS);</pre>
<p>Then we need to create a new projection map for the cursor. A projection map
can be used to "rename" columns. In our case, we will replace
<code>BooksStore.Book._ID</code>, <code>BooksStore.Book.TITLE</code> and
<code>BooksStore.Book.AUTHORS</code> with <code>LiveFolders._ID</code>,
<code>LiveFolders.TITLE</code> and <code>LiveFolders.DESCRIPTION</code>:</p>
<pre>private static final HashMap&lt;string, string=""&gt; LIVE_FOLDER_PROJECTION_MAP;
static {
LIVE_FOLDER_PROJECTION_MAP = new HashMap&lt;string, string=""&gt;();
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID +
" AS " + LiveFolders._ID);
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE +
" AS " + LiveFolders.NAME);
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS +
" AS " + LiveFolders.DESCRIPTION);
}</pre>
<p>Because we are providing a title and a description for each row, Home will
automatically display each item of the live folder with two lines of text.
Finally, we implement the <code>query()</code> method by supplying our
projection map to the SQL query builder:</p>
<pre>public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (URI_MATCHER.match(uri)) {
// ...
case LIVE_FOLDER_BOOKS:
qb.setTables("books");
qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}</pre>
<p>You can now compile and deploy the application, go to the Home screen and
try to add a live folder. You can add a books live folder to your Home screen
and when you open it, see the list of all of your books, with their
titles and authors, and all it took was a few lines of code:</p>
<img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 267px; height: 400px;" src="images/device.png" alt="" id="BLOGGER_PHOTO_ID_5323293545495859234" border="0"></p>
<p>The live folders API is extremely simple and relies only on intents and
content URI. If you want to see more examples of live folders
implementation, you can read the source code of the <a href="http://android.git.kernel.org/?p=platform/packages/apps/Contacts.git;a=tree;h=refs/heads/cupcake;hb=cupcake">Contacts application</a> and of the <a href="http://android.git.kernel.org/?p=platform/packages/providers/ContactsProvider.git;a=tree;h=refs/heads/cupcake;hb=cupcake">Contacts provider</a>.</p><p>You can also download the result of our exercise, the <a href="http://jext.free.fr/CupcakeShelves.zip">modified version of Shelves with live folders support</a>.</p>

View File

@ -0,0 +1,97 @@
page.title=Live Wallpapers
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}resources/samples/CubeLiveWallpaper/index.html">Live Wallpaper
sample</a></li>
</ol>
</div>
</div>
<p>Starting with Android 2.1 (API Level 7), users can now enjoy <em>live
wallpapers</em> &mdash; richer, animated, interactive backgrounds &mdash; on
their home screens. A live wallpaper is very similar to a normal Android
application and has access to all the facilities of the platform: SGL (2D
drawing), OpenGL (3D drawing), GPS, accelerometers, network access, etc. The
live wallpapers included on Nexus One demonstrate the use of some of these APIs
to create fun and interesting user experiences. For instance, the Grass
wallpaper uses the phone's location to compute sunrise and sunset times in order
to display the appropriate sky.</p>
<img src="images/live_wallpapers_small.png" style="align:center" />
<p>Creating your own live wallpaper is easy, especially if you have had
previous experience with <a
href="../../../reference/android/view/SurfaceView.html"><code>SurfaceView</code></a> or <a
href="../../../reference/android/graphics/Canvas.html"><code>Canvas</code></a>.
To learn how to create a live wallpaper, you should check out the <a
href="../samples/CubeLiveWallpaper/index.html">CubeLiveWallpaper sample code</a>.</p>
<p>In terms of implementation, a live wallpaper is very similar to a regular
Android <a href="../../../reference/android/app/Service.html">service</a>. The
only difference is the addition of a new method, <a
href="../../../reference/android/service/wallpaper/WallpaperService.html#onCreateEngine()">{@code
onCreateEngine()}</a>, whose goal is to create a <a
href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html">
<code>WallpaperService.Engine</code></a>. The engine is responsible for
handling the lifecycle and drawing of a wallpaper. The system provides a surface
on which you can draw, just like you would with a <code>SurfaceView</code></a>.
Drawing a wallpaper can be very expensive so you should optimize your code
as much as possible to avoid using too much CPU, not only for battery life
but also to avoid slowing down the rest of the system. That is also why the
most important part of the lifecycle of a wallpaper is <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onVisibilityChanged%28boolean%29">when it becomes invisible</a>.
When invisible, such as when the user launches an application that covers
the home screen, a wallpaper must stop all activity.</p>
<p>The engine can also implement several methods to interact with the user
or the home application. For instance, if you want your wallpaper to scroll
along when the user swipes from one home screen to another, you can use <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onOffsetsChanged%28float,%20float,%20float,%20float,%20int,%20int%29"><code>onOffsetsChanged()</code></a>.
To react to touch events, simply implement <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onTouchEvent%28android.view.MotionEvent%29"><code>onTouchEvent(MotionEvent)</code></a>.
Finally, applications can send arbitrary commands to the live wallpaper.
Currently, only the standard home application sends commands to the <a
href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onCommand%28java.lang.String,%20int,%20int,%20int,%20android.os.Bundle,%20boolean%29"><code>onCommand()</code></a>
method of the live wallpaper:</p>
<ul>
<li><code>android.wallpaper.tap</code>: When the user taps an empty space
on the workspace. This command is interpreted by the Nexus and Water live
wallpapers to make the wallpaper react to user interaction. For instance,
if you tap an empty space on the Water live wallpaper, new ripples appear
under your finger.</li>
<li><code>android.home.drop</code>: When the user drops an icon or a widget
on the workspace. This command is also interpreted by the Nexus and Water
live wallpapers.</li>
</ul>
<p>If you are developing a live wallpaper, remember that the feature is
supported only on Android 2.1 (API level 7) and higher versions of the platform.
To ensure that your application can only be installed on devices that support
live wallpapers, remember to add the following to the application's manifest
before publishing to Android Market:</p>
<ul>
<li><code>&lt;uses-sdk android:minSdkVersion="7" /&gt;</code>, which indicates
to Android Market and the platform that your application requires Android 2.1 or
higher. For more information, see the <a href="../../../guide/appendix/api-levels.html">API
Levels</a> and the documentation for the
<a href="../../../guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
element.</li>
<li><code>&lt;uses-feature android:name="android.software.live_wallpaper" /&gt;</code>,
which tells Android Market that your application includes a live wallpaper
Android Market uses this feature as a filter, when presenting users lists of
available applications. When you declaring this feature, Android Market
displays your application only to users whose devices support live wallpapers,
while hiding it from other devices on which it would not be able to run. For
more information, see the documentation for the
<a href="../../../guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
element.</li>
</ul>
<p>Many great live wallpapers are already available on Android Market and
we can't wait to see more!</p>

View File

@ -0,0 +1,263 @@
page.title=Onscreen Input Methods
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}resources/articles/creating-input-method.html">Creating an Input
Method</a></li>
<li><a href="{@docRoot}resources/samples/SoftKeyboard/index.html">Soft Keyboard sample</a></li>
</ol>
</div>
</div>
<p>Starting from Android 1.5, the Android platform offers an Input Method
Framework (IMF) that lets you create on-screen input methods such as software
keyboards. This article provide an overview of what Android input method editors
(IMEs) are and what an application needs to do to work well with them. The IMF
is designed to support new classes of Android devices, such as those without
hardware keyboards, so it is important that your application works well with the
IMF and offers a great experience for users.</p>
<h3>What is an input method?</h3>
<p>The Android IMF is designed to support a variety of IMEs, including soft
keyboard, hand-writing recognizers, and hard keyboard translators. Our focus,
however, will be on soft keyboards, since this is the kind of input method that
is currently part of the platform.</p>
<p>A user will usually access the current IME by tapping on a text view to
edit, as shown here in the home screen:</p>
<img style="width: 320px; height: 480px; margin-right: 10px;" src="images/on-screen-inputs_004.png">
<img style="width: 320px; height: 480px;" src="images/on-screen-inputs.png">
<p>The soft keyboard is positioned at the bottom of the screen over the
application's window. To organize the available space between the application
and IME, we use a few approaches; the one shown here is called <em>pan and
scan</em>, and simply involves scrolling the application window around so that
the currently focused view is visible. This is the default mode, since it is the
safest for existing applications.</p>
<p>Most often the preferred screen layout is a <em>resize</em>, where the
application's window is resized to be entirely visible. An example is shown
here, when composing an e-mail message:</p>
<img style="width: 320px; height: 480px; margin-right: 10px;" src="images/on-screen-inputs_005.png">
<img style="width: 320px; height: 480px;" src="images/on-screen-inputs_003.png">
<p>The size of the application window is changed so that none of it is hidden by
the IME, allowing full access to both the application and IME. This of course
only works for applications that have a resizeable area that can be reduced to
make enough space, but the vertical space in this mode is actually no less than
what is available in landscape orientation, so very often an application can
already accommodate it.</p>
<p>The final major mode is <em>fullscreen</em> or <em>extract</em>
mode. This is used when the IME is too large to reasonably share space
with the underlying application. With the standard IMEs, you will only
encounter this situation when the screen is in a landscape orientation,
although other IMEs are free to use it whenever they desire. In this
case the application window is left as-is, and the IME simply displays
fullscreen on top of it, as shown here:</p>
<img style="width: 480px; height: 320px; margin-right: 10px; margin-bottom: 10px;" src="images/on-screen-inputs_006.png">
<img style="width: 480px; height: 320px;" src="images/on-screen-inputs_002.png">
<p>Because the IME is covering the application, it has its own editing area,
which shows the text actually contained in the application. There are also some
limited opportunities the application has to customize parts of the IME (the
"done" button at the top and enter key label at the bottom) to improve the user
experience.</p>
<h3>Basic XML attributes for controlling IMEs</h3>
<p>There are a number of things the system does to try to help existing
applications work with IMEs as well as possible, such as:</p>
<ul>
<li>Use pan and scan mode by default, unless it can reasonably guess that
resize mode will work by the existence of lists, scroll views, etc.</li>
<li>Analyze the various existing TextView attributes to guess at the kind of
content (numbers, plain text, etc) to help the soft keyboard display an
appropriate key layout.</li>
<li>Assign a few default actions to the fullscreen IME, such as "next field"
and "done".</li>
</ul>
<p>There are also some simple things you can do in your application that will
often greatly improve its user experience. Except where explicitly mentioned,
these will work in any Android platform version, even those previous to Android
1.5 (since they will simply ignore these new options).</p>
<h4>Specifying each EditText control's input type</h4>
<p>The most important thing for an application to do is to use the new
<code>android:inputType</code>
attribute on each <code>EditText</code>. The attribute provides much richer
information
about the text content. This attribute actually replaces many existing
attributes (<code>android:</code><code>password</code>,
<code>android:</code><code>singleLine</code>,
<code>android:</code><code>numeric</code>,
<code>android:</code><code>phoneNumber</code>,
<code>android:</code><code>capitalize</code>,
<code>android:</code><code>autoText</code>, and
<code>android:</code><code>editable</code>). If you specify the older attributes
and the new <code>android:inputType</code> attribute, the system uses
<code>android:inputType</code> and ignores the others. </p>
<p>The <code>android:inputType</code> attribute has three pieces:</p>
<ul>
<li>The <em>class</em> is the overall interpretation of characters. The
currently supported classes are <code>text</code> (plain text),
<code>number</code> (decimal number), <code>phone</code> (phone number), and
<code>datetime</code> (a date or time).</li>
<li>The <em>variation</em> is a further refinement on the class. In the
attribute you will normally specify the class and variant together, with the
class as a prefix. For example, <code>textEmailAddress</code> is a text field
where the user will enter something that is an e-mail address (foo@bar.com) so
the key layout will have an '@' character in easy access, and
<code>numberSigned</code> is a numeric field with a sign. If only the class is
specified, then you get the default/generic variant.</li>
<li>Additional <em>flags</em> can be specified that supply further refinement.
These flags are specific to a class. For example, some flags for the
<code>text</code> class are <code>textCapSentences</code>,
<code>textAutoCorrect</code>, and <code>textMultiline</code>.</li>
</ul>
<p>As an example, here is the new EditText for the IM application's message text view:</p>
<pre> &lt;EditText android:id="@+id/edtInput"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
android:imeOptions="actionSend|flagNoEnterAction"
android:maxLines="4"
android:maxLength="2000"
android:hint="@string/compose_hint"/&gt;</pre>
<p>A full description of all of the input types can be found in the
documentation. It is important to make use of the correct input types that are
available, so that the soft keyboard can use the optimal keyboard layout for the
text the user will be entering.</p>
<h4>Enabling resize mode and other window features</h4>
<p>The second most important thing for your app to do is to specify the overall
behavior of your window in relation to the input method. The most visible aspect
of this is controlling resize vs. pan and scan mode, but there are other things
you can do as well to improve your user experience.</p>
<p>You will usually control this behavior through the
<code>android:windowSoftInputMode</code> attribute on each
<code>&lt;activity&gt;</code> definition in your
<code>AndroidManifest.xml</code>. Like the input type, there are a couple
different pieces of data that can be specified here by combining them
together:</p>
<ul>
<li>The window adjustment mode is specified with either
<code>adjustResize</code> or <code>adjustPan</code>. It is highly recommended
that you always specify one or the other.</li>
<li>You can further control whether the IME will be shown automatically when
your activity is displayed and other situations where the user moves to it. The
system won't automatically show an IME by default, but in some cases it can be
convenient for the user if an application enables this behavior. You can request
this with <code>stateVisible</code>. There are also a number of other state
options for finer-grained control that you can find in the documentation.</li>
</ul>
<p>A typical example of this field can be see in the edit contact activity,
which ensures it is resized and automatically displays the IME for the user:</p>
<pre> &lt;activity name="EditContactActivity"
android:windowSoftInputMode="stateVisible|adjustResize"&gt;
...
&lt;/activity&gt;</pre>
<p class="note"><strong>Note:</strong>Starting from Android 1.5 (API Level 3),
the platform offers a new method,
{@link android.view.Window#setSoftInputMode(int mode)},
that non-Activity windows can use to control their behavior. Calling this method
in your will make your application incompatible with previous versions of the
Android platform.</p>
<h4>Controlling the action buttons</h4>
<p>The final customization we will look at is the "action" buttons in the IME.
There are currently two types of actions:</p>
<ul>
<li>The enter key on a soft keyboard is typically bound to an action when not
operating on a mult-line edit text. For example, on the G1 pressing the hard
enter key will typically move to the next field or the application will
intercept it to execute an action; with a soft keyboard, this overloading of the
enter key remains, since the enter button just sends an enter key event.</li>
<li>When in fullscreen mode, an IME may also put an additional action button to
the right of the text being edited, giving the user quick access to a common
application operation.</li>
</ul>
<p>These options are controlled with the <code>android:imeOptions</code>
attribute on <code>TextView</code>. The value you supply here can be any
combination of:</p>
<ul>
<li>One of the pre-defined action constants (<code>actionGo</code>,
<code>actionSearch</code>, <code>actionSend</code>, <code>actionNext</code>,
<code>actionDone</code>). If none of these are specified, the system will infer
either <code>actionNext</code> or <code>actionDone</code> depending on whether
there is a focusable field after this one; you can explicitly force no action
with <code>actionNone</code>.</li>
<li>The <code>flagNoEnterAction</code> option tells the IME that the action
should <em>not</em> be available on the enter key, even if the text itself is
not multi-line. This avoids having unrecoverable actions like (send) that can be
accidentally touched by the user while typing.</li>
<li>The <code>flagNoAccessoryAction</code> removes the action button from the
text area, leaving more room for text.</li><li>The <code>flagNoExtractUi</code>
completely removes the text area, allowing the application to be seen behind
it.</li>
</ul>
<p>The previous IM application message view also provides an example of an
interesting use of <code>imeOptions</code>, to specify the send action but not
let it be shown on the enter key:</p>
<pre>android:imeOptions="actionSend|flagNoEnterAction"</pre>
<h3>APIs for controlling IMEs</h3>
<p>For more advanced control over the IME, there are a variety of new APIs you
can use. Unless special care is taken (such as by using reflection), using these
APIs will cause your application to be incompatible with previous versions of
Android, and you should make sure you specify
<code>android:minSdkVersion="3"</code> in your manifest. For more information,
see the documentation for the <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a
> manifest element.</p>
<p>The primary API is the new <code>android.view.inputmethod.InputMethodManager</code> class, which you can retrieve with <code>Context.getSystemService()</code>.
It allows you to interact with the global input method state, such as
explicitly hiding or showing the current IME's input area.</p>
<p>There are also new window flags controlling input method interaction, which you can control through the existing <code>Window.addFlags()</code> method and new <code>Window.setSoftInputMode()</code> method. The <code>PopupWindow</code>
class has grown corresponding methods to control these options on its
window. One thing in particular to be aware of is the new <code>WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM</code> constant, which is used to control whether a window is on top of or behind the current IME.</p>
<p>Most of the interaction between an active IME and application is done through the <code>android.view.inputmethod.InputConnection</code>
class. This is the API an application implement, which an IME calls to
perform the appropriate edit operations on the application. You won't
normally need to worry about this, since <code>TextView</code> provides its own implementation for itself.</p>
<p>There are also a handful of new <code>View</code> APIs, the most important of these being<code> onCreateInputConnection()</code> which creates a new <code>InputConnection</code> for an IME (and fills in an <code>android.view.inputmethod.EditorInfo</code>
structure with your input type, IME options, and other data); again,
most developers won't need to worry about this, since TextView takes
care of it for you.</p>

View File

@ -0,0 +1,147 @@
page.title=Painless Threading
@jd:body
<p>This article discusses the threading model used by Android applications and how applications can ensure best UI performance by spawning worker threads to handle long-running operations, rather than handling them in the main thread. The article also explains the API that your application can use to interact with Android UI toolkit components running on the main thread and spawn managed worker threads. </p>
<h3>The UI thread</h3>
<p>When an application is launched, the system creates a thread called
"main" for the application. The main thread, also called the <em>UI
thread</em>, is very important because it is in charge of dispatching the
events to the appropriate widgets, including drawing events.
It is also the thread where your application interacts with running
components of the Android UI toolkit. </p>
<p>For instance, if you touch the a button on screen, the UI thread dispatches
the touch event to the widget, which in turn sets its pressed state and
posts an invalidate request to the event queue. The UI thread dequeues
the request and notifies the widget to redraw itself.</p>
<p>This single-thread model can yield poor performance unless your application
is implemented properly. Specifically, if everything is happening in a single
thread, performing long operations such as network access or database
queries on the UI thread will block the whole user interface. No event
can be dispatched, including drawing events, while the long operation
is underway. From the user's perspective, the application appears hung.
Even worse, if the UI thread is blocked for more than a few seconds
(about 5 seconds currently) the user is presented with the infamous "<a href="http://developer.android.com/guide/practices/design/responsiveness.html">application not responding</a>" (ANR) dialog.</p>
<p>If you want to see how bad this can look, write a simple application
with a button that invokes <code>Thread.sleep(2000)</code> in its
<a href="http://developer.android.com/reference/android/view/View.OnClickListener.html">OnClickListener</a>.
The button will remain in its pressed state for about 2 seconds before
going back to its normal state. When this happens, it is very easy for
the user to <em>perceive</em> the application as slow.</p>
<p>To summarize, it's vital to the responsiveness of your application's UI to
keep the UI thread unblocked. If you have long operations to perform, you should
make sure to do them in extra threads (<em>background</em> or <em>worker</em>
threads). </p>
<p>Here's an example of a click listener downloading an image over the
network and displaying it in an <a href="http://developer.android.com/reference/android/widget/ImageView.html">ImageView</a>:</p>
<pre class="prettyprint">public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}</pre>
<p>At first, this code seems to be a good solution to your problem, as it does
not block the UI thread. Unfortunately, it violates the single-threaded model
for the UI: the Android UI toolkit is <em>not thread-safe</em> and must always
be manipulated on the UI thread. In this piece of code above, the
<code>ImageView</code> is manipulated on a worker thread, which can cause really
weird problems. Tracking down and fixing such bugs can be difficult and
time-consuming.</p>
<p>Android offers several ways to access the UI
thread from other threads. You may already be familiar with some of
them but here is a comprehensive list:</p>
<ul>
<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable) Activity.runOnUiThread(Runnable)}</li>
<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li>
<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable, long)}</li>
<li>{@link android.os.Handler}</li>
</ul>
<p>You can use any of these classes and methods to correct the previous code example:</p>
<pre class="prettyprint">public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}</pre>
<p>Unfortunately,
these classes and methods could also tend to make your code more complicated
and more difficult to read. It becomes even worse when your implement
complex operations that require frequent UI updates. </p>
<p>To remedy this problem, Android 1.5 and later platforms offer a utility class
called {@link android.os.AsyncTask}, that simplifies the creation of
long-running tasks that need to communicate with the user interface.</p>
<p>An <code>AsyncTask</code> equivalent is also available for applications that
will run on Android 1.0 and 1.1. The name of the class is <a
href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/
curiouscreature/android/shelves/util/UserTask.java">UserTask</a>. It offers the
exact same API and all you have to do is copy its source code in your
application.</p>
<p>The goal of <code>AsyncTask</code> is to take care of thread management for
you. Our previous example can easily be rewritten with
<code>AsyncTask</code>:</p>
<pre class="prettyprint">public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask&lt;string, void,="" bitmap=""&gt; {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}</pre>
<p>As you can see, <code>AsyncTask</code> <em>must</em> be used by subclassing
it. It is also very important to remember that an <code>AsyncTask</code>
instance has to be created on the UI thread and can be executed only once. You
can read the <a
href="http://developer.android.com/reference/android/os/AsyncTask.html">
AsyncTask documentation</a> for a full understanding on how to use this class,
but here is a quick overview of how it works:</p>
<ul>
<li>You can specify the type, using generics, of the parameters, the progress values and the final value of the task</li>
<li>The method <a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground%28Params...%29">doInBackground()</a> executes automatically on a worker thread</li>
<li><a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPreExecute%28%29">onPreExecute()</a>, <a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute%28Result%29">onPostExecute()</a> and <a href="http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate%28Progress...%29">onProgressUpdate()</a> are all invoked on the UI thread</li>
<li>The value returned by <a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground%28Params...%29">doInBackground()</a> is sent to <a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute%28Result%29">onPostExecute()</a></li>
<li>You can call <a href="http://developer.android.com/reference/android/os/AsyncTask.html#publishProgress%28Progress...%29">publishProgress()</a> at anytime in <a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground%28Params...%29">doInBackground()</a> to execute <a href="http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate%28Progress...%29">onProgressUpdate()</a> on the UI thread</li><li>You can cancel the task at any time, from any thread</li>
</ul>
<p>In addition to the official documentation, you can read several complex examples in the source code of Shelves (<a href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/activity/ShelvesActivity.java">ShelvesActivity.java</a> and <a href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/activity/AddBookActivity.java">AddBookActivity.java</a>) and Photostream (<a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/LoginActivity.java">LoginActivity.java</a>, <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java">PhotostreamActivity.java</a> and <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/ViewPhotoActivity.java">ViewPhotoActivity.java</a>). We highly recommend reading the source code of <a href="http://code.google.com/p/shelves/">Shelves</a> to see how to persist tasks across configuration changes and how to cancel them properly when the activity is destroyed.</p>
<p>Regardless of whether or not you use <a href="http://developer.android.com/reference/android/os/AsyncTask.html">AsyncTask</a>,
always remember these two rules about the single thread model: </p>
<ol>
<li>Do not block the UI thread, and
<li>Make sure that you access the Android UI toolkit <em>only</em> on the UI thread.
</ol>
<p><code>AsyncTask</code> just makes it easier to do both of these things.</p>

View File

@ -0,0 +1,167 @@
page.title=Quick Search Box
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/search/index.html">Search</a></li>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary
sample</a></li>
</ol>
</div>
</div>
<div class="figure" style="width:233px">
<img src="images/qsb_002.png" alt="" height="350" />
</div>
<p>Starting with Android 1.6, the platform includes support for Quick Search
Box (QSB), a powerful, system-wide search framework. Quick Search Box makes it
possible for users to quickly and easily find what they're looking for, both on
their devices and on the web. It suggests content on your device as you type,
like apps, contacts, browser history, and music. It also offers results from the
web search suggestions, local business listings, and other info from
Google, such as stock quotes, weather, and flight status. All of this is
available right from the home screen, by tapping on Quick Search Box.</p>
<p>What
we're most excited about with this new feature is the ability for you,
the developers, to leverage the QSB framework to provide quicker and
easier access to the content inside your apps. Your apps can provide
search suggestions that will surface to users in QSB alongside other
search results and suggestions. This makes it possible for users to
access your application's content from outside your application—for
example, from the home screen.</p>
<p class="note"><strong>Note:</strong> The code fragments in this document are
related to a sample app called <a
href="{@docRoot}resources/samples/SearchableDictionary/index.html"
title="Searchable Dictionary">Searchable Dictionary</a>. The app is
available for Android 1.6 and later platforms.</p>
<h3>The story before now: searching within your app</h3>
<p>Platform releases versions previous to Android 1.6 already provided a mechanism
that let you expose search and search suggestions in your app, as described in
the docs for {@link android.app.SearchManager}. That mechanism has not changed
and requires the following two things in your
<code>AndroidManifest.xml</code>:</p>
<p>1) In your <code>&lt;activity&gt;</code>, an intent filter, and a reference
to a <code>searchable.xml</code> file (described below):</p>
<pre class="prettyprint">&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.SEARCH" /&gt;
&lt;category android:name="android.intent.category.DEFAULT" /&gt;
&lt;/intent-filter&gt;
&lt;meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" /&gt;</pre>
<p>2) A content provider that can provide search suggestions according to the
URIs and column formats specified by the
<a href="{@docRoot}reference/android/app/SearchManager.html#Suggestions">Search Suggestions</a>
section of the SearchManager docs:</p>
<pre class="prettyprint">&lt;!-- Provides search suggestions for words and their definitions. --&gt;
&lt;provider android:name="DictionaryProvider"
android:authorities="dictionary"
android:syncable="false" /&gt;</pre>
<p>In the <code>searchable.xml</code> file, you specify a few things about how
you want the search system to present search for your app, including the
authority of the content provider that provides suggestions for the user as they
type. Here's an example of the <code>searchable.xml</code> of an Android app
that provides search suggestions within its own activities:</p>
<pre class="prettyprint">&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:searchSuggestAuthority="dictionary"
android:searchSuggestIntentAction="android.intent.action.VIEW"&gt;
&lt;/searchable&gt;</pre>
<p>Note that the <code>android:searchSuggestAuthority</code> attribute refers to
the authority of the content provider we declared in
<code>AndroidManifest.xml</code>.</p>
<p>For more details on this, see the
<a href="{@docRoot}reference/android/app/SearchManager.html#SearchabilityMetadata">Searchability Metadata
section</a> of the of the SearchManager docs.</p>
<h3>Including your app in Quick Search Box</h3>
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>Searchable Dictionary Sample App</h2>
<p>Quick Search Box provides a really cool way to make it easier and faster for
users to access your app's content. To help you get your app started with it,
we've created a sample app that simply provides access to a small dictionary of
words in QSB. The app is called Searchable Dictionary, and we encourage you to
<a href="{@docRoot}resources/samples/SearchableDictionary/index.html">check it
out</a>.</p>
</div>
</div>
<p>In Android 1.6, we added a new attribute to the metadata for searchables:
<code>android:includeInGlobalSearch</code>. By specifying this as
<code>"true"</code> in your <code>searchable.xml</code>, you allow QSB to pick
up your search suggestion content provider and include its suggestions along
with the rest (if the user enables your suggestions from the system search
settings).</p>
<p>You should also specify a string value for
<code>android:searchSettingsDescription</code>, which describes to users what
sorts of suggestions your app provides in the system settings for search.</p>
<pre class="prettyprint">&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
<span style="background: rgb(255, 255, 0) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;">android:searchSettingsDescription="@string/settings_description"</span>
<span style="background: rgb(255, 255, 0) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;">android:includeInGlobalSearch="true"</span>
android:searchSuggestAuthority="dictionary"
android:searchSuggestIntentAction="android.intent.action.VIEW"&gt;
&lt;/searchable&gt;</pre>
<p>These new attributes are supported only in Android 1.6 and later.</p>
<h3>What to expect</h3>
<p>The
first and most important thing to note is that when a user installs an
app with a suggestion provider that participates in QSB, this new app
will <em>not</em> be enabled for QSB by default. The user can choose
to enable particular suggestion sources from the system settings for
search (by going to "Search" &gt; "Searchable items" in settings).</p>
<p>You
should consider how to handle this in your app. Perhaps show a notice
that instructs the user to visit system settings and enable your app's
suggestions.</p>
<p>Once the user enables your searchable item, the
app's suggestions will have a chance to show up in QSB, most likely
under the "more results" section to begin with. As your app's
suggestions are chosen more frequently, they can move up in the list.</p>
<img src="images/qsb.png" style="width: 233px; height: 349.5px;">
<img id="k0vw" src="images/qsb_003.png" style="width: 233px; height: 349.5px;">
<h3>Shortcuts</h3>
<p>One
of our objectives with QSB is to make it faster for users to access the
things they access most often. One way we've done this is by
'shortcutting' some of the previously chosen search suggestions, so
they will be shown immediately as the user starts typing, instead of
waiting to query the content providers. Suggestions from your app may
be chosen as shortcuts when the user clicks on them.</p>
<p>For dynamic suggestions that may wish to change their content (or become invalid)
in the future, you can provide a 'shortcut id'. This tells QSB to query
your suggestion provider for up-to-date content for a suggestion after
it has been displayed. For more details on how to manage shortcuts, see
the Shortcuts section
<a href="{@docRoot}reference/android/app/SearchManager.html#ExposingSearchSuggestionsToQuickSearchBox">within the SearchManager docs</a>.</p>

View File

@ -0,0 +1,90 @@
page.title=Speech Input
@jd:body
<p> People love their mobile phones because they can stay in touch wherever they
are. That means not just talking, but e-mailing, texting, microblogging, and so
on. </p>
<p>Speech input adds another dimension to staying in touch.
Google's Voice Search application, which is pre-installed on many Android devices,
provides powerful features like "search by voice" and voice shortcuts like "Navigate to." Further
enhancing the voice experience, Android 2.1 introduces a <a
href="http://www.youtube.com/watch?v=laOlkD8LmZw">
voice-enabled keyboard</a>, which makes it even easier
to stay connected. Now you can dictate your message instead of typing it. Just
tap the new microphone button on the keyboard, and you can speak in just about
any context in which you would normally type. </p>
<p> We believe speech can
fundamentally change the mobile experience. We would like to invite every
Android application developer to consider integrating speech input capabilities
via the Android SDK. One of our favorite apps in the Market that integrates
speech input is <a href="http://www.handcent.com/">Handcent SMS</a>,
because you can dictate a reply to any SMS with a
quick tap on the SMS popup window. Here is Speech input integrated into
Handcent SMS:</p>
<img src="images/speech-input.png"/>
<p> The Android SDK makes it easy to integrate speech input directly into your
own application. Just copy and paste from this <a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/VoiceRecognition.html">sample
application</a> to get
started. The sample application first verifies that the target device is able
to recognize speech input:</p>
<pre>
// Check to see if a recognition activity is present
PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(
new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (activities.size() != 0) {
speakButton.setOnClickListener(this);
} else {
speakButton.setEnabled(false);
speakButton.setText("Recognizer not present");
}
</pre>
<p>
The sample application then uses {@link
android.app.Activity#startActivityForResult(android.content.Intent, int)
startActivityForResult()} to broadcast an intent that requests voice
recognition, including an extra parameter that specifies one of two language
models. The voice recognition application that handles the intent processes the
voice input, then passes the recognized string back to your application by
calling the {@link android.app.Activity#onActivityResult(int, int,
android.content.Intent) onActivityResult()} callback. </p>
<p>Android is an open platform, so your application can potentially make
use of any speech recognition service on the device that's registered to receive
a {@link android.speech.RecognizerIntent}. Google's Voice Search application,
which is pre-installed on
many Android devices, responds to a <em>RecognizerIntent</em> by displaying the
"Speak
now" dialog and streaming audio to Google's servers -- the same servers used
when a user taps the microphone button on the search widget or the voice-enabled
keyboard. Voice Search is installed on all the major
US devices, and it's also available on Market. You can check whether Voice
Search is installed in
<strong>Settings > Applications > Manage applications</strong>. </p>
<p> One important tip: for speech input to be as accurate as possible, it's
helpful to have an idea of what words are likely to be spoken. While a message
like "Mom, I'm writing you this message with my voice!" might be appropriate for
an email or SMS message, you're probably more likely to say something like
"weather in Mountain View" if you're using Google Search. You can make sure your
users have the best experience possible by requesting the appropriate
<em>language model:</em> {@link
android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM free_form} for
dictation, or {@link android.speech.RecognizerIntent#LANGUAGE_MODEL_WEB_SEARCH
web_search} for shorter, search-like phrases. We developed the "free form"
model to improve dictation accuracy for the voice keyboard,
while the "web search" model is used when users want to search by voice. </p>
<p> Google's servers currently support English, Mandarin Chinese, and Japanese.
The web search model is available in all three languages, while free-form has
primarily been optimized for English. As we work hard to support more models in
more languages, and to improve the accuracy of the speech recognition technology
we use in our products, Android developers who integrate speech capabilities
directly into their applications can reap the benefits as well. </p>

View File

@ -0,0 +1,149 @@
page.title=Updating the UI from a Timer
@jd:body
<img style="margin: 1.5em; float: right;" src="images/JFlubber.png" alt="" id="BLOGGER_PHOTO_ID_5135098660116808706" border="0">
<p><strong>Background</strong>: While developing my first useful
(though small) application for Android, which was a port of an existing
utility I use when podcasting, I needed a way of updating a clock
displayed on the UI at regular intervals, but in a lightweight and CPU
efficient way.</p>
<p><strong>Problem</strong>: In the original application I used
java.util.Timer to update the clock, but that class is not such a good
choice on Android. Using a Timer introduces a new thread into the
application for a relatively minor reason. Thinking in terms of mobile
applications often means re-considering choices that you might make
differently for a desktop application with relatively richer resources
at its disposal. We would like to find a more efficient way of updating
that clock.</p>
<p><strong>The Application</strong>: The original application is a
Java Swing and SE application. It is like a stopwatch with a lap timer
that we use when recording podcasts; when you start the recording, you
start the stopwatch. Then for every mistake that someone makes, you hit
the flub button. At the end you can save out the bookmarked mistakes
which can be loaded into the wonderful
<a href="http://audacity.sourceforge.net/" title="Audacity">Audacity</a>
audio editor as a labels track. You can then see where all of the mistakes
are in the recording and edit them out.</p>
<p>The article describing it is: <a href="http://www.developer.com/java/ent/print.php/3589961" title="http://www.developer.com/java/ent/print.php/3589961">http://www.developer.com/java/ent/print.php/3589961</a></p>
<p>In the original version, the timer code looked like this:</p>
<pre>class UpdateTimeTask extends TimerTask {
public void run() {
long millis = System.currentTimeMillis() - startTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
timeLabel.setText(String.format("%d:%02d", minutes, seconds));
}
}</pre><p>And in the event listener to start this update, the following Timer() instance is used:
</p><pre>if(startTime == 0L) {
startTime = evt.getWhen();
timer = new Timer();
timer.schedule(new UpdateTimeTask(), 100, 200);
}</pre>
<p>In particular, note the 100, 200 parameters. The first parameter
means wait 100 ms before running the clock update task the first time.
The second means repeat every 200ms after that, until stopped. 200 ms
should not be too noticeable if the second resolution happens to fall
close to or on the update. If the resolution was a second, you could
find the clock sometimes not updating for close to 2 seconds, or
possibly skipping a second in the counting, it would look odd).</p>
<p>When I ported the application to use the Android SDKs, this code
actually compiled in Eclipse, but failed with a runtime error because
the Timer() class was not available at runtime (fortunately, this was
easy to figure out from the error messages). On a related note, the
String.format method was also not available, so the eventual solution
uses a quick hack to format the seconds nicely as you will see.</p>
<p>Fortunately, the role of Timer can be replaced by the
android.os.Handler class, with a few tweaks. To set it up from an event
listener:</p>
<pre>private Handler mHandler = new Handler();
...
OnClickListener mStartListener = new OnClickListener() {
public void onClick(View v) {
if (mStartTime == 0L) {
mStartTime = System.currentTimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}
}
};</pre>
<p>A couple of things to take note of here. First, the event doesn't
have a .getWhen() method on it, which we handily used to set the start
time for the timer. Instead, we grab the System.currentTimeMillis().
Also, the Handler.postDelayed() method only takes one time parameter,
it doesn't have a "repeating" field. In this case we are saying to the
Handler "call mUpdateTimeTask() after 100ms", a sort of fire and forget
one time shot. We also remove any existing callbacks to the handler
before adding the new handler, to make absolutely sure we don't get
more callback events than we want.</p>
<p>But we want it to repeat, until we tell it to stop. To do this, just
put another postDelayed at the tail of the mUpdateTimeTask run()
method. Note also that Handler requires an implementation of Runnable,
so we change mUpdateTimeTask to implement that rather than extending
TimerTask. The new clock updater, with all these changes, looks like
this:</p>
<pre>private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
final long start = mStartTime;
long millis = SystemClock.uptimeMillis() - start;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
if (seconds &lt; 10) {
mTimeLabel.setText("" + minutes + ":0" + seconds);
} else {
mTimeLabel.setText("" + minutes + ":" + seconds);
}
mHandler.postAtTime(this,
start + (((minutes * 60) + seconds + 1) * 1000));
}
};</pre>
<p>and can be defined as a class member field.</p>
<p>The if statement is just a way to make sure the label is set to
10:06 instead of 10:6 when the seconds modulo 60 are less than 10
(hopefully String.format() will eventually be available). At the end of
the clock update, the task sets up another call to itself from the
Handler, but instead of a hand-wavy 200ms before the update, we can
schedule it to happen at a particular wall-clock time — the line: start
+ (((minutes * 60) + seconds + 1) * 1000) does this.</p>
<p>All we need now is a way to stop the timer when the stop button
is pressed. Another button listener defined like this:</p>
<pre>OnClickListener mStopListener = new OnClickListener() {
public void onClick(View v) {
mHandler.removeCallbacks(mUpdateTimeTask);
}
};</pre>
<p>will make sure that the next callback is removed when the stop button
is pressed, thus interrupting the tail iteration.</p>
<p>Handler is actually a better choice than Timer for another reason
too. The Handler runs the update code as a part of your main thread,
avoiding the overhead of a second thread and also making for easy
access to the View hierarchy used for the user interface. Just remember
to keep such tasks small and light to avoid slowing down the user
experience.</p>

View File

@ -0,0 +1,138 @@
page.title=Touch Mode
@jd:body
<p>This article explains the <em>touch mode</em>, one of the most
important principles of Android's UI toolkit.</p>
<p>The touch mode is a state of the view hierarchy that depends solely on the
user interaction with the phone. By itself, the touch mode is something very
easy to understand as it simply indicates whether the last user interaction was
performed with the touch screen. For example, if you are using an
Android-powered device, selecting a widget with the trackball will take you out
of touch mode; however, if you touch a button on the screen with your finger,
you will enter touch mode. When the user is not in touch mode, we talk about the
trackball mode, navigation mode or keyboard navigation, so do not be surprised
if you encounter these terms. </p>
<p>There is only one API directly related to touch mode,
{@link android.view.View#isInTouchMode() View.isInTouchMode()}.</p>
<p>Sounds easy enough, right? Oddly enough, touch mode is deceivingly simple and
the consequences of entering touch mode are far greater than you might
think. Let's look at some of the reasons why.</p>
<h4>Touch Mode, Selection, and Focus</h4>
<p>Designing a UI toolkit for mobile devices is difficult because of the various
interaction mechanisms they provide. Some devices offer only 12 keys, some have
a touch screen, some require a stylus, some have both a touch screen and a
keyboard. Based on the hardware capabilities of the he user can interact with
your application using different mechanisms, so we had to think very hard about
all the possible issues that could arise. One issue led us to create the touch
mode.</p>
<p>Imagine a simple application, <a href="{@docRoot}resources/samples/index.html">ApiDemos</a>
for example, that shows a list of text items. The user can freely
navigate through the list using the trackball but also, alternatively, scroll
and fling the list using the touch screen. The issue in this scenario is
how to handle the selection properly when the user manipulates the list
through the touch screen. </p>
<p>In this case, if the user selects an item at the top of the list and then
flings the list towards the bottom, what should happen to the selection? Should
it remain on the item and scroll off the screen? What should happen if the user
then decided to move the selection with the trackball? Or worse, what should
happen if the user presses the trackball to act upon the currently selected
item, which is not shown on screen anymore? </p>
<p>After careful consideration, we decided to remove the selection altogether,
when the user manipulates the UI through the touch screen.</p>
<p>In touch mode, there is no focus and no selection. Any selected item in a
list of in a grid becomes unselected as soon as the user enters touch
mode. Similarly, any focused widgets become unfocused when the user
enters touch mode. The image below illustrates what happens when the
user touches a list after selecting an item with the trackball.</p>
<img style="margin: 0px 7px;" src="images/list02.png" alt="" id="BLOGGER_PHOTO_ID_5272753165743060962" border="0">
<img style="margin: 0px 7px;" src="images/list01.png" alt="" id="BLOGGER_PHOTO_ID_5272753357441963442" border="0">
<p>To
make things more natural for the user, the framework knows how to
resurrect the selection/focus whenever the user leaves touch mode. For
instance, in the example above, if the user were to use the trackball
again, the selection would reappear on the previously-selected item.
This is why some developers are confused when they create a custom view
and start receiving key events only after moving the trackball once:
their application is in touch mode, and they need to use the trackball
to exit touch mode and resurrect the focus.</p>
<p>The relationship between touch mode, selection, and focus means you must not
rely on selection and/or focus to exist in your application. A very common
problem with new Android developers is to rely on
{@link android.widget.AdapterView#getSelectedItemPosition() ListView.getSelectedItemPosition()}.
In touch mode, this method will return
{@link android.widget.AdapterView#INVALID_POSITION INVALID_POSITION}.
You should instead use click listeners (see
{@link android.widget.AdapterView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)})
or the choice mode (see
{@link android.widget.ListView#setChoiceMode(int)}).</p>
<h4>Focusable in Touch Mode</h4>
<p>In general, focus doesn't exist in touch mode. However, focus can exist in
touch mode in a very special way called <em>focusable</em>. This special mode
was created for widgets that receive text input, such as
{@link android.widget.EditText} or, when filtering is enabled,
{@link android.widget.ListView}. The focusable mode is what lets the user enter text
inside a text field on the screen, without first selecting it with the trackball
or their finger.</p>
<p>When a user
touches the screen, the application will enter touch mode if it wasn't
in touch mode already. What happens during the transition to
touch mode depends on what the user touched, and what currently has
focus. If the user touches a widget that is focusable in touch
mode, that widget will receive focus. Otherwise, any currently
focused widget will not retain focus unless it is focusable in touch
mode. For instance, in the picture below, when the user touches
the screen, the input text field receives the focus.</p>
<img style="margin: 0px 7px;" src="images/text_field.png" alt="" id="BLOGGER_PHOTO_ID_5272755475757779154" border="0">
<p>Fousable in touch mode (see
{@link android.view.View#setFocusableInTouchMode(boolean) View.setFocusableInTouchMode})
is a property that you can set yourself, either from code or from XML.
However, you should use it sparingly and only in very specific situations,
because it breaks consistency with the normal behavior of the Android UI. A game
is a good example of an application that could make good use of the focusable in
touch mode property. MapView, if used in fullscreen as in Google Maps, is
another good example of where you can use focusable in touch mode correctly.</p>
<p>Below is another example of a focusable in touch mode widget. When the user
taps an <code>AutoCompleteTextView</code> suggestion with his finger, the focus
remains on the input text field:</p>
<img style="margin: 0px 7px;" src="images/search01.png" alt="" id="BLOGGER_PHOTO_ID_5272756689821626962" border="0">
<img style="margin: 0px 7px;" src="images/search02.png" alt="" id="BLOGGER_PHOTO_ID_5272756246104676754" border="0">
<p>Developers new to Android often think that focusable in touch mode is the
solution they need to "fix" the problem of "disappearing" selection/focus. We
really encourage you to think very hard before using it. If used incorrectly, it
can make your application behave differently from the rest of the system and
simply throw off the user's habits. The Android framework contains all the tools
you need to handle user interactions without using focusable in touch mode. For
example, instead of trying to make <code>ListView</code> always keep its
selection, simply use the appropriate choice mode, as shown in
{@link android.widget.ListView#setChoiceMode(int)}.
<h4>Touch Mode Cheat Sheet</h4>
<p>Do:</p>
<ul>
<li>Remain consistent with the core applications</li><li>Use the appropriate feature if you need persistent selection (radio button, check box, the <code>ListView</code> choice mode, etc.)</li>
<li>Use focusable in touch mode if you write a game</li>
</ul>
<p>Don't:</p>
<ul><li>Do not try to keep the focus or selection in touch mode</li></ul>

View File

@ -0,0 +1,62 @@
page.title=Tracking Memory Allocations
@jd:body
<p>Writing efficient mobile applications is not always straightforward. In
particular, Android applications rely on automatic memory management handled by
Dalvik's garbage collector, which can sometimes cause performance issues if you
are not careful with memory allocations.</p>
<p>In a performance-sensitive code path, such as the layout or drawing method of
a view or the logic code of a game, any allocation comes at a price. After too
many allocations, the garbage collector will kick in and stop your application
to let it free some memory. Most of the time, garbage collections happen fast
enough for you not to notice. However, if a collection happens while you are
scrolling through a list of items or while you are trying to defeat a foe in a
game, you may suddenly see a drop in performance/responsiveness of the
application. It's not unusual for a garbage collection to take 100 to 200 ms.
For comparison, a smooth animation needs to draw each frame in 16 to 33 ms. If
the animation is suddenly interrupted for 10 frames, you can be certain that
your users will notice.</p>
<p>Most of the time, garbage collection occurs because of tons of small,
short-lived objects and some garbage collectors, like generational garbage
collectors, can optimize the collection of these objects so that the application
does not get interrupted too often. The Android garbage collector is
unfortunately not able to perform such optimizations and the creation of
short-lived objects in performance critical code paths is thus very costly for
your application.</p>
<p>To help you avoid frequent garbage collections, the Android SDK ships with a
very useful tool called <em>allocation tracker</em>. This tool is part of DDMS,
which you must have already used for debugging purposes. To start using the
allocation tracker, you must first launch the standalone version of DDMS, which
can be found in the <code>tools/</code> directory of the SDK. The version of
DDMS included in the Eclipse plugin does not offer you ability to use the
allocation tracker yet.</p>
<p>Once DDMS is running, simply select your application process and then click
the <em>Allocation Tracker</em> tab. In the new view, click <em>Start
Tracking</em> and then use your application to make it execute the code paths
you want to analyze. When you are ready, click <em>Get Allocations</em>. A list
of allocated objects will be shown in the first table. By clicking on a line you
can see, in the second table, the stack trace that led to the allocation. Not
only you will know what type of object was allocated, but also in which thread,
in which class, in which file and at which line. The following screenshot shows
the allocations performed by <a
href="http://code.google.com/p/shelves">Shelves</a> while scrolling a
ListView.</p>
<a href="images/ddms_allocation_trackerl.png">
<img style="cursor:hand;width: 320px; height: 250px;" src="images/ddms_allocation_tracker.png" border="0" alt="" />
</a>
<p>Even though it is not necessary &mdash; and sometimes not possible &mdash; to
remove all allocations for your performance critical code paths. the allocation
tracker will help you identify important issues in your code. For instance, a
common mistake I have seen in many applications is to create a new
<code>Paint</code> object on every draw. Moving the paint into an instance field
is a simple fix that helps performance a lot. I highly encourage you to peruse
the <a href="http://source.android.com/">Android source code</a> to see how we
reduce allocations in performance-critical code paths. You will also thus
discover the APIs Android provide to help you reuse objects.</p>

View File

@ -0,0 +1,241 @@
page.title=Using Text-to-Speech
@jd:body
<p>Starting with Android 1.6 (API Level 4), the Android platform includes a new
Text-to-Speech (TTS) capability. Also known as "speech synthesis", TTS enables
your Android device to "speak" text of different languages.</p>
<p>Before we explain how to use the TTS API itself, let's first review a few
aspects of the engine that will be important to your TTS-enabled application. We
will then show how to make your Android application talk and how to configure
the way it speaks.</p>
<h3>Languages and resources</h3>
<p>The TTS engine that ships with the Android platform supports a number of
languages: English, French, German, Italian and Spanish. Also, depending on
which side of the Atlantic you are on, American and British accents for English
are both supported.</p>
<p>The TTS engine needs to know which language to speak, as a word like "Paris",
for example, is pronounced differently in French and English. So the voice and
dictionary are language-specific resources that need to be loaded before the
engine can start to speak.</p>
<p>Although all Android-powered devices that support the TTS functionality ship
with the engine, some devices have limited storage and may lack the
language-specific resource files. If a user wants to install those resources,
the TTS API enables an application to query the platform for the availability of
language files and can initiate their download and installation. So upon
creating your activity, a good first step is to check for the presence of the
TTS resources with the corresponding intent:</p>
<pre>Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);</pre>
<p>A successful check will be marked by a <code>CHECK_VOICE_DATA_PASS</code>
result code, indicating this device is ready to speak, after the creation of
our
{@link android.speech.tts.TextToSpeech} object. If not, we need to let the user
know to install the data that's required for the device to become a
multi-lingual talking machine! Downloading and installing the data is
accomplished by firing off the ACTION_INSTALL_TTS_DATA intent, which will take
the user to Android Market, and will let her/him initiate the download.
Installation of the data will happen automatically once the download completes.
Here is an example of what your implementation of
<code>onActivityResult()</code> would look like:</p>
<pre>private TextToSpeech mTts;
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
mTts = new TextToSpeech(this, this);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}</pre>
<p>In the constructor of the <code>TextToSpeech</code> instance we pass a
reference to the <code>Context</code> to be used (here the current Activity),
and to an <code>OnInitListener</code> (here our Activity as well). This listener
enables our application to be notified when the Text-To-Speech engine is fully
loaded, so we can start configuring it and using it.</p>
<h4>Languages and Locale</h4>
<p>At Google I/O 2009, we showed an <a title="Google I/O 2009, TTS
demonstration" href="http://www.youtube.com/watch?v=uX9nt8Cpdqg#t=6m17s"
id="rnfd">example of TTS</a> where it was used to speak the result of a
translation from and to one of the 5 languages the Android TTS engine currently
supports. Loading a language is as simple as calling for instance:</p>
<pre>mTts.setLanguage(Locale.US);</pre><p>to load and set the language to
English, as spoken in the country "US". A locale is the preferred way to specify
a language because it accounts for the fact that the same language can vary from
one country to another. To query whether a specific Locale is supported, you can
use <code>isLanguageAvailable()</code>, which returns the level of support for
the given Locale. For instance the calls:</p>
<pre>mTts.isLanguageAvailable(Locale.UK))
mTts.isLanguageAvailable(Locale.FRANCE))
mTts.isLanguageAvailable(new Locale("spa", "ESP")))</pre>
<p>will return TextToSpeech.LANG_COUNTRY_AVAILABLE to indicate that the language
AND country as described by the Locale parameter are supported (and the data is
correctly installed). But the calls:</p>
<pre>mTts.isLanguageAvailable(Locale.CANADA_FRENCH))
mTts.isLanguageAvailable(new Locale("spa"))</pre>
<p>will return <code>TextToSpeech.LANG_AVAILABLE</code>. In the first example,
French is supported, but not the given country. And in the second, only the
language was specified for the Locale, so that's what the match was made on.</p>
<p>Also note that besides the <code>ACTION_CHECK_TTS_DATA</code> intent to check
the availability of the TTS data, you can also use
<code>isLanguageAvailable()</code> once you have created your
<code>TextToSpeech</code> instance, which will return
<code>TextToSpeech.LANG_MISSING_DATA</code> if the required resources are not
installed for the queried language.</p>
<p>Making the engine speak an Italian string while the engine is set to the
French language will produce some pretty <i>interesting </i>results, but it will
not exactly be something your user would understand So try to match the
language of your application's content and the language that you loaded in your
<code>TextToSpeech</code> instance. Also if you are using
<code>Locale.getDefault()</code> to query the current Locale, make sure that at
least the default language is supported.</p>
<h3>Making your application speak</h3>
<p>Now that our <code>TextToSpeech</code> instance is properly initialized and
configured, we can start to make your application speak. The simplest way to do
so is to use the <code>speak()</code> method. Let's iterate on the following
example to make a talking alarm clock:</p>
<pre>String myText1 = "Did you sleep well?";
String myText2 = "I hope so, because it's time to wake up.";
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, null);
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, null);</pre>
<p>The TTS engine manages a global queue of all the entries to synthesize, which
are also known as "utterances". Each <code>TextToSpeech</code> instance can
manage its own queue in order to control which utterance will interrupt the
current one and which one is simply queued. Here the first <code>speak()</code>
request would interrupt whatever was currently being synthesized: the queue is
flushed and the new utterance is queued, which places it at the head of the
queue. The second utterance is queued and will be played after
<code>myText1</code> has completed.</p>
<h4>Using optional parameters to change the playback stream type</h4>
<p>On Android, each audio stream that is played is associated with one stream
type, as defined in
{@link android.media.AudioManager android.media.AudioManager}. For a talking
alarm clock, we would like our text to be played on the
<code>AudioManager.STREAM_ALARM</code> stream type so that it respects the alarm
settings the user has chosen on the device. The last parameter of the speak()
method allows you to pass to the TTS engine optional parameters, specified as
key/value pairs in a HashMap. Let's use that mechanism to change the stream type
of our utterances:</p>
<pre>HashMap&lt;String, String&gt; myHashAlarm = new HashMap();
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_ALARM));
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);</pre>
<h4>Using optional parameters for playback completion callbacks</h4>
<p>Note that <code>speak()</code> calls are asynchronous, so they will return
well before the text is done being synthesized and played by Android, regardless
of the use of <code>QUEUE_FLUSH</code> or <code>QUEUE_ADD</code>. But you might
need to know when a particular utterance is done playing. For instance you might
want to start playing an annoying music after <code>myText2</code> has finished
synthesizing (remember, we're trying to wake up the user). We will again use an
optional parameter, this time to tag our utterance as one we want to identify.
We also need to make sure our activity implements the
<code>TextToSpeech.OnUtteranceCompletedListener</code> interface:</p>
<pre>mTts.setOnUtteranceCompletedListener(this);
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_ALARM));
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
"end of wakeup message ID");
// myHashAlarm now contains two optional parameters
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);</pre>
<p>And the Activity gets notified of the completion in the implementation
of the listener:</p>
<pre>public void onUtteranceCompleted(String uttId) {
if (uttId == "end of wakeup message ID") {
playAnnoyingMusic();
}
}</pre>
<h4>File rendering and playback</h4>
<p>While the <code>speak()</code> method is used to make Android speak the text
right away, there are cases where you would want the result of the synthesis to
be recorded in an audio file instead. This would be the case if, for instance,
there is text your application will speak often; you could avoid the synthesis
CPU-overhead by rendering only once to a file, and then playing back that audio
file whenever needed. Just like for <code>speak()</code>, you can use an
optional utterance identifier to be notified on the completion of the synthesis
to the file:</p>
<pre>HashMap&lt;String, String&gt; myHashRender = new HashMap();
String wakeUpText = "Are you up yet?";
String destFileName = "/sdcard/myAppCache/wakeUp.wav";
myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, wakeUpText);
mTts.synthesizeToFile(wakuUpText, myHashRender, destFileName);</pre>
<p>Once you are notified of the synthesis completion, you can play the output
file just like any other audio resource with
{@link android.media.MediaPlayer android.media.MediaPlayer}.</p>
<p>But the <code>TextToSpeech</code> class offers other ways of associating
audio resources with speech. So at this point we have a WAV file that contains
the result of the synthesis of "Wake up" in the previously selected language. We
can tell our TTS instance to associate the contents of the string "Wake up" with
an audio resource, which can be accessed through its path, or through the
package it's in, and its resource ID, using one of the two
<code>addSpeech()</code> methods:</p>
<pre>mTts.addSpeech(wakeUpText, destFileName);</pre>
<p>This way any call to speak() for the same string content as
<code>wakeUpText</code> will result in the playback of
<code>destFileName</code>. If the file is missing, then speak will behave as if
the audio file wasn't there, and will synthesize and play the given string. But
you can also take advantage of that feature to provide an option to the user to
customize how "Wake up" sounds, by recording their own version if they choose
to. Regardless of where that audio file comes from, you can still use the same
line in your Activity code to ask repeatedly "Are you up yet?":</p>
<pre>mTts.speak(wakeUpText, TextToSpeech.QUEUE_ADD, myHashAlarm);</pre>
<h4>When not in use...</h4><p>The text-to-speech functionality relies on a
dedicated service shared across all applications that use that feature. When you
are done using TTS, be a good citizen and tell it "you won't be needing its
services anymore" by calling <code>mTts.shutdown()</code>, in your Activity
<code>onDestroy()</code> method for instance.</p>
<h3>Conclusion</h3>
<p>Android now talks, and so can your apps. Remember that in order for
synthesized speech to be intelligible, you need to match the language you select
to that of the text to synthesize. Text-to-speech can help you push your app in
new directions. Whether you use TTS to help users with disabilities, to enable
the use of your application while looking away from the screen, or simply to
make it cool, we hope you'll enjoy this new feature.</p>

Some files were not shown because too many files have changed in this diff Show More