diff options
Diffstat (limited to 'docs/html/guide/topics')
21 files changed, 5858 insertions, 328 deletions
diff --git a/docs/html/guide/topics/advanced/aidl.jd b/docs/html/guide/topics/advanced/aidl.jd new file mode 100644 index 0000000..fef46ec --- /dev/null +++ b/docs/html/guide/topics/advanced/aidl.jd @@ -0,0 +1,387 @@ +page.title=Android Interface Definition Language (AIDL) +@jd:body + + + +<p>AIDL (Android Interface Definition Language) is similar to other IDLs you might have +worked with. It allows you to define the programming interface that both +the client and service agree upon in order to communicate with each other and allows for +interprocess communication (IPC). On Android, one process can not normally access the +memory of another process. So to talk, they need to decompose their objects into primitives that the +operating system can understand, and "marshall" the object across that boundary for you. The code to +do that marshalling is tedious to write, so Android handles it for you with AIDL.</p> + +<p class="note"><strong>Note:</strong> Using AIDL is necessary only if you allow clients from +different applications to access your service for IPC and want to handle multithreading in your +service. If you do not need to perform IPC across +different applications, you should create your interface <a href="Binder">implementing a +Binder</a> or, if you want to perform IPC, but do not need to handle multithreading, then you +should implement your interface <a href="#Messenger">using a Messenger</a>.</p> + +<p>Before you begin designing your AIDL interface, be aware that calls on to an AIDL interface are +direct function calls. You can not generally make assumptions about the thread in which the call +will happen. What happens is different depending on whether the call is from a thread in the +local process, or coming from a remote process. Specifically:</p> + +<ul> +<li>Calls from the local process are executed in the same thread that is making the call. If this is +your main UI thread, that thread will continue executing into the aidl interface. If it is another +thread, that is one that will be executing your code. Thus if only local threads are accessing the +interface, you can completely control which threads are executing in it (but if that is the case, +why are you defining an aidl interface at all?).</li> + +<li>Calls from a remote process are dispatched from a thread pool the platform maintains inside of +your own process. You must be prepared for incoming calls from unknown threads, with multiple calls +happening at the same time. In other words, an implementation of an aidl interface must be +completely thread-safe.</li> + +<li>The "oneway" keyword modifies the behavior of remote calls. When used, a remote call will not +block until its call completes; it simply sends the transaction data and immediately returns. The +implementation of the interface will eventually receive this as a regular call from the {@link +android.os.Binder} thread pool as a normal remote call. If "oneway" is used with a local call, +there is no impact and the call is still synchronous.</li> +</ul> + + +<h2 id="Defining">Defining an AIDL Interface</h2> + +<p>You must define your AIDL interface in an {@code .aidl} file using the Java +programming language syntax, then save it in the source code (in the {@code src/} directory) of both +the application hosting the service and any other application that will bind to the service.</p> + +<p>When you build the projects containing the {@code .aidl} file, the Android SDK tools generate an +{@link android.os.IBinder} class based on your AIDL interface (and saves the file in the {@code +gen/} directory). This class defines the APIs you can call to perform RPC as an interface—you +must implement the interface in your service.</p> + +<p>To create a bounded service using AIDL, follow these steps:</p> +<ol> + <li><a href="#CreateAidl">Create the .aidl file</a> + <p>This file defines the programming interface with method signatures.</p> + </li> + <li><a href="#ImplementTheInterface">Implement the interface</a> + <p>The Android SDK tools generate an interface in the Java programming language, based on your +{@code .aidl} file. This interface has an inner abstract class named {@code Stub} that extends +{@link android.os.Binder} and implements methods from your AIDL interface. You must extend the +{@code Stub} class and implement the methods.</p> + </li> + <li><a href="#ExposeTheInterface">Expose the interface to clients</a> + <p>Implement a {@link android.app.Service Service} and override {@link +android.app.Service#onBind onBind()} to return your implementation of the {@code Stub} +class.</p> + </li> +</ol> + +<p class="caution"><strong>Caution:</strong> Any changes that you make to your AIDL interface after +your first release must remain backward compatible in order to avoid breaking other applications +that use your service. That is, because your {@code .aidl} file must be copied to other applications +in order for them to access your service's interface, you must maintain support for the original +interface.</p> + + +<h3 id="CreateAidl">1. Create the .aidl file</h3> + +<p>AIDL uses a simple syntax that lets you declare an interface with one or more methods that can +take parameters and return values. The parameters and return values can be of any type, even other +AIDL-generated interfaces.</p> + +<p>The syntax for the {@code .aidl} file uses the Java programming language. The file defines a +single interface and requires only the interface declaration and method signatures.</p> + +<p>By default, AIDL supports the following data types:</p> + +<ul> + <li>All primitive types in the Java programming language ({@code int}, {@code long}, {@code +char}, {@code boolean}, etc.)</li> + <li>{@link java.lang.String}</li> + <li>{@link java.lang.CharSequence}</li> + <li>{@link java.util.List} + <p>All elements in the {@link java.util.List} must be one of the supported data types in this +list or one of the other AIDL-generated interfaces or parcelables you've declared. A {@link +java.util.List} may optionally be used as a "generic" class (e.g. <code>List<String></code>). +The actual concrete class that the other side will receive will always be an {@link +java.util.ArrayList}, although the method will be generated to use the {@link +java.util.List} interface.</p> + </li> + <li>{@link java.util.Map} + <p>All elements in the {@link java.util.Map} must be one of the supported data types in this +list or one of the other AIDL-generated interfaces or parcelables you've declared. Generic maps, +(such as those of the form +{@code Map<String,Integer>} are not supported. The actual concrete class that the other side +will receive will always be a {@link java.util.HashMap}, although the method will be generated to +use the {@link java.util.Map} interface.</p> + </li> +</ul> + +<p>You must include an {@code import} statement for each additional type not listed above, even if +they are defined in the same package as your interface.</p> + +<p>When defining methods for your service interface, be aware that:</p> +<ul> + <li>Methods can take zero or more parameters, and return a value or void.</li> + <li>All non-primitive parameters require a directional tag indicating which way the data will go. +Either <code>in</code>, <code>out</code>, or <code>inout</code> (see the example below). + <p>Primitives are <code>in</code> by default, and cannot be otherwise.</p> + <p class="caution"><strong>Caution:</strong> You should limit the direction to what is truly +needed, because marshalling parameters is expensive.</p></li> + <li>All code comments included in the {@code .aidl} file are included in the generated {@link +android.os.IBinder} interface (except for comments before the import and package +statements).</li> +</ul> + +<p>Here is an example {@code .aidl} file:</p> + +<pre> +// IRemoteService.aidl +package com.example.android; + +// Declare any non-default types here with import statements + +/** Example service interface */ +interface IRemoteService { + /** Request the process ID of this service, to do evil things with it. */ + int getPid(); + + /** Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, + double aDouble, String aString); +} +</pre> + +<p>Simply save your {@code .aidl} file in your project's {@code src/} directory and when you +build your application, the SDK tools will generate the binder class file in your project's +{@code gen/} directory. The generated file name matches the {@code .aidl} file name, but with a +{@code .java} extension (for example, {@code IRemoteService.aidl} results in {@code +IRemoteService.java}).</p> + +<p>If you use Eclipse, the incremental build generates the binder class almost immediately. If you +do not use Eclipse, then the Ant tool generates the binder class next time you build your +application—you should build your project with <code>ant debug</code> (or <code>ant +release</code>) as soon as you're finished writing the {@code .aidl} file, so that your code can +link against the generated class.</p> + + +<h3 id="ImplementTheInterface">2. Implement the interface</h3> + +<p>When you build your application, the Android SDK tools generate a {@code .java} interface file +named after your {@code .aidl} file. The generated interface includes a subclass named {@code Stub} +that is an abstract implementation of its parent interface (for example, {@code +YourInterface.Stub}) and declares all the methods from the {@code .aidl} file.</p> + +<p class="note"><strong>Note:</strong> {@code Stub} also +defines a few helper methods, most notably {@code asInterface()}, which takes an {@link +android.os.IBinder} (usually the one passed to a client's {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method) and +returns an instance of the stub interface. See the section <a href="#calling">Calling an IPC +Method</a> for more details on how to make this cast.</p></p> + +<p>To implement the interface generated from the {@code .aidl}, extend the generated {@link +android.os.Binder} interface (for example, {@code YourInterface.Stub}) and implement the methods +inherited from the {@code .aidl} file.</p> + +<p>Here is an example implementation of an interface called {@code IRemoteService} (defined by the +{@code IRemoteService.aidl} example, above) using an anonymous instance:</p> + +<pre> +private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { + public int getPid(){ + return Process.myPid(); + } + public void basicTypes(int anInt, long aLong, boolean aBoolean, + float aFloat, double aDouble, String aString) { + // Does nothing + } +}; +</pre> + +<p>Now the {@code mBinder} is an instance of the {@code Stub} class (a {@link android.os.Binder}), +which defines the RPC interface for the service. In the next step, this instance is exposed to +clients so they can interact with the service.</p> + +<p>There are a few rules you should be aware of when implementing your AIDL interface: </p> +<ul> + <li>Incoming calls are not guaranteed to be executed on the main thread, so you need to think +about multithreading from the start and properly build your service to be thread-safe.</li> + <li>By default, RPC calls are synchronous. If you know that the service takes more than a few +milliseconds to complete a request, you should not call it from the activity's main thread, because +it might hang the application (Android might display an "Application is Not Responding" +dialog)—you should usually call them from a separate thread in the client. </li> + <li>No exceptions that you throw are sent back to the caller.</li> + <li>Only methods are supported; you cannot expose static fields in AIDL.</li> +</ul> + + +<h3 id="ExposeTheInterface">3. Expose the interface to clients</h3> + +<p>Once you've implemented the interface for your service, you need to expose it to +clients so they can bind to it. To expose the interface +for your service, extend {@link android.app.Service Service} and implement {@link +android.app.Service#onBind onBind()} to return an instance of your class that implements +the generated {@code Stub} (as discussed in the previous section). Here's an example +service that exposes the {@code IRemoteService} example interface to clients. </p> + +<pre> +public class RemoteService extends Service { + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public IBinder onBind(Intent intent) { + // Return the interface + return mBinder; + } + + private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { + public int getPid(){ + return Process.myPid(); + } + public void basicTypes(int anInt, long aLong, boolean aBoolean, + float aFloat, double aDouble, String aString) { + // Does nothing + } + }; +} +</pre> + +<p>Now, when a client (such as an activity) calls {@link android.content.Context#bindService +bindService()} to connect to this service, the client's {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback receives the +{@code mBinder} instance returned by the service's {@link android.app.Service#onBind onBind()} +method.</p> + +<p>The client must also have access to the interface class, so if the client and service are in +separate applications, then the client's application must have a copy of the {@code .aidl} file +in its {@code src/} directory (which generates the {@code android.os.Binder} +interface—providing the client access to the AIDL methods).</p> + +<p>When the client receives the {@link android.os.IBinder} in the {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback, it must call +<code><em>YourServiceInterface</em>.Stub.asInterface(service)</code> to cast the returned +parameter to <code><em>YourServiceInterface</em></code> type. For example:</p> + +<pre> +IRemoteService mIRemoteService; +private ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + // Following the example above for an AIDL interface, + // this gets an instance of the IRemoteInterface, which we can use to call on the service + mIRemoteService = IRemoteService.Stub.asInterface(service); + } + + // Called when the connection with the service disconnects unexpectedly + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "onServiceDisconnected"); + } +}; +</pre> + +<p>For more sample code, see the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code +RemoteService.java}</a> class in <a +href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p> + + + + + + + + +<h2 id="PassingObjects">Passing Objects over IPC</h2> + +<p>If you have a class that you would like to send from one process to another through +an IPC interface, you can do that. However, you must ensure that the code for your class is +available to the other side of the IPC and the class must support the {@link +android.os.Parcelable} interface, in order for the objects to be decomposed into primitives and +marshalled across processes by the Android system.</p> + +<p>There are five parts to making a class support the {@link android.os.Parcelable} protocol:</b> +<ol> +<li>Make your class implement the {@link android.os.Parcelable} interface.</li> +<li>Implement {@link android.os.Parcelable#writeToParcel writeToParcel}, which takes the +current state of the object and writes it to a {@link android.os.Parcel}.</li> +<li>Add a static field called <code>CREATOR</code> to your class which is an object implementing +the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.</li> +<li>Finally, create an {@code .aidl} file that declares your parcelable class (as shown for the +{@code Rect.aidl} file, below). + <p>If you are using a custom build process, do <em>not</em> add the {@code .aidl} file to your +build. Similar to a header file in the C language, this {@code .aidl} file isn't compiled.</p></li> +</ol> + +<p>AIDL will use these methods and fields in the code it generates to marshall and unmarshall +your objects.</p> + +<p>For example, here is a {@code Rect.aidl} file to create a {@code Rect} class that's +parcelable:</p> + +<pre> +package android.graphics; + +// Declare Rect so AIDL can find it and knows that it implements +// the parcelable protocol. +parcelable Rect; +</pre> + +<p>And here is an example of how the {@link android.graphics.Rect} class implements the +{@link android.os.Parcelable} protocol.</p> + +<pre> +import android.os.Parcel; +import android.os.Parcelable; + +public final class Rect implements Parcelable { + public int left; + public int top; + public int right; + public int bottom; + + public static final Parcelable.Creator<Rect> CREATOR = new +Parcelable.Creator<Rect>() { + public Rect createFromParcel(Parcel in) { + return new Rect(in); + } + + public Rect[] newArray(int size) { + return new Rect[size]; + } + }; + + public Rect() { + } + + private Rect(Parcel in) { + readFromParcel(in); + } + + public void writeToParcel(Parcel out) { + out.writeInt(left); + out.writeInt(top); + out.writeInt(right); + out.writeInt(bottom); + } + + public void readFromParcel(Parcel in) { + left = in.readInt(); + top = in.readInt(); + right = in.readInt(); + bottom = in.readInt(); + } +} +</pre> + +<p>The marshalling in the {@code Rect} class is pretty simple. Take a look at the other +methods on {@link android.os.Parcel} to see the other kinds of values you can write +to a Parcel.</p> + +<p class="warning"><strong>Warning:</strong> Don't forget the security implications of receiving +data from other processes. In this case, the {@code Rect} will read four numbers from the {@link +android.os.Parcel}, but it is up to you to ensure that these are within the acceptable range of +values for whatever the caller is trying to do. See <a +href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> for more +information about how to keep your application secure from malware.</p> + diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd index a095087..1658fa6 100644 --- a/docs/html/guide/topics/fundamentals.jd +++ b/docs/html/guide/topics/fundamentals.jd @@ -19,6 +19,7 @@ page.title=Application Fundamentals <li><a href="#lmodes">Launch modes</a></li> <li><a href="#clearstack">Clearing the stack</a></li> <li><a href="#starttask">Starting tasks</a></li> + <li><a href="#commonpatterns">Common patterns</a></li> </ol></li> <li><a href="#procthread">Processes and Threads</a> <ol> @@ -51,10 +52,9 @@ page.title=Application Fundamentals <p> Android applications are written in the Java programming language. The compiled Java code — along with any data and resource -files required by the application — is bundled by the -<a href="{@docRoot}guide/developing/tools/aapt.html"><code>aapt</code> -tool</a> into an <i>Android package</i>, an archive file -marked by an {@code .apk} suffix. This file is the vehicle +files required by the application — is bundled into an +<i>Android package</i>, an archive file +marked by an {@code .apk} suffix. This file is the vehicle for distributing the application and installing it on mobile devices; it's the file users download to their devices. All the code in a single {@code .apk} file is considered to be one <i>application</i>. @@ -294,8 +294,8 @@ onActivityResult()}</code> method. <li><p>A service is started (or new instructions are given to an ongoing service) by passing an Intent object to <code>{@link android.content.Context#startService Context.startService()}</code>. -Android calls the service's <code>{@link android.app.Service#onStart -onStart()}</code> method and passes it the Intent object.</p> +Android calls the service's <code>{@link android.app.Service#onStartCommand +onStartCommand()}</code> method and passes it the Intent object.</p> <p> Similarly, an intent can be passed to <code>{@link @@ -424,7 +424,7 @@ elements for broadcast receivers, and <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> elements for content providers. Activities, services, and content providers that are not declared in the manifest are not visible to the system and are -consequently never run. However, broadcast receivers can either be +consequently never run. However, broadcast receivers can either be declared in the manifest, or they can be created dynamically in code (as {@link android.content.BroadcastReceiver} objects) and registered with the system by calling @@ -892,6 +892,60 @@ See <a href="#clearstack">Clearing the stack</a>, earlier. </p> +<h3 id="commonpatterns">Common patterns</h3> + +<p> +In most cases an application won't use any flags or special features. +This gives the standard interaction the user expects: launching the application +brings any existing task to the foreground, or starts the main activity in +a new task if there isn't one. +</p> + +<p> +If an application posts notifications, it needs to decide how the user's +selection of a notification should impact any currently running task. The +current suggested behavior is that any current tasks be completely removed, +replaced with a new task containing a stack of activities representing where +the user is jumping in to the app. This can be accomplished with a combination +of the {@link android.app.PendingIntent#getActivities PendingIntent.getActivities()} +method and {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK Intent.FLAG_ACTIVITY_CLEAR_TASK}. +</p> + +<p> +For example, here is sample code to build an array of Intents to launch an +application into an activity three levels deep. The first Intent is always +the main Intent of the application as started by the launcher. The exact +details of the Intent data will of course depend on your application. +</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/StatusBarNotifications.java + intent_array} + +<p> +In some cases an application may not want to directly launch its application +from a notification, but instead go to a intermediate summary activity. To +accomplish this, the summary activity should be given a task affinity that +is different from the main application (one will typically give it no affinity, +that is "") so that it does not get launched into any existing application task. +</p> + +{@sample development/samples/ApiDemos/AndroidManifest.xml no_task_affinity} + +<p> +The PendingIntent to launch this then does not need to supply anything special: +</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java + pending_intent} + +<p> +If an application implements an app widget, it should generally use the same +approach as the first one for notifications: when the user taps on the app +widget it should throw away any current task of the application and start a +new task with potentially multiple activities representing the state the +user is jumping in to. +</p> + <h2 id="procthread">Processes and Threads</h2> <p> @@ -1510,9 +1564,9 @@ a music playback service could create the thread where the music will be played in {@code onCreate()}, and then stop the thread in {@code onDestroy()}.</li> <li><p>The <b>active lifetime</b> of a service begins with a call to -<code>{@link android.app.Service#onStart onStart()}</code>. This method +<code>{@link android.app.Service#onStartCommand onStartCommand()}</code>. This method is handed the Intent object that was passed to {@code startService()}. -The music service would open the Intent to discover which music to +The music service would open the Intent to discover which music to play, and begin the playback.</p> <p> @@ -1527,7 +1581,7 @@ services, whether they're started by <code>{@link android.content.Context#startService Context.startService()}</code> or <code>{@link android.content.Context#bindService Context.bindService()}</code>. -However, {@code onStart()} is called only for services started by {@code +However, {@code onStartCommand()} is called only for services started by {@code startService()}. </p> @@ -1631,7 +1685,7 @@ to the activity that the user is interacting with.</p></li> <li><p>It has a {@link android.app.Service} object that's executing one of its lifecycle callbacks (<code>{@link android.app.Service#onCreate -onCreate()}</code>, <code>{@link android.app.Service#onStart onStart()}</code>, +onCreate()}</code>, <code>{@link android.app.Service#onStartCommand onStartCommand()}</code>, or <code>{@link android.app.Service#onDestroy onDestroy()}</code>).</p></li> <li><p>It has a {@link android.content.BroadcastReceiver} object that's diff --git a/docs/html/guide/topics/fundamentals/activities.jd b/docs/html/guide/topics/fundamentals/activities.jd new file mode 100644 index 0000000..b616ab8 --- /dev/null +++ b/docs/html/guide/topics/fundamentals/activities.jd @@ -0,0 +1,762 @@ +page.title=Activities +parent.title=Application Fundamentals +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>Quickview</h2> +<ul> + <li>An activity provides a user interface for a single screen in your application</li> + <li>Activities can move into the background and then be resumed with their state restored</li> +</ul> + +<h2>In this document</h2> +<ol> + <li><a href="#Creating">Creating an Activity</a> + <ol> + <li><a href="#UI">Implementing a user interface</a></li> + <li><a href="#Declaring">Declaring the activity in the manifest</a></li> + </ol> + </li> + <li><a href="#StartingAnActivity">Starting an Activity</a> + <ol> + <li><a href="#StartingAnActivityForResult">Starting an Activity for a Result</a></li> + </ol> + </li> + <li><a href="#Lifecycle">Managing the Activity Lifecycle</a> + <ol> + <li><a href="#ImplementingLifecycleCallbacks">Implementing the lifecycle callbacks</a></li> + <li><a href="#SavingActivityState">Saving activity state</a></li> + <li><a href="#ConfigurationChanges">Handling configuration changes</a></li> + <li><a href="#CoordinatingActivities">Coordinating activities</a></li> + </ol> + </li> +</ol> + +<h2>Key classes</h2> +<ol> + <li>{@link android.app.Activity}</li> +</ol> + +<h2>See also</h2> +<ol> + <li><a href="{@docRoot}resources/tutorials/hello-world.html">Hello World Tutorial</a></li> + <li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack">Tasks and Back +Stack</a></li> +</ol> + +</div> +</div> + + + +<p>An {@link android.app.Activity} is an application component that provides a screen with which +users can interact in order to do something, such as dial the phone, take a photo, send an email, or +view a map. Each activity is given a window in which to draw its user interface. The window +typically fills the screen, but may be smaller than the screen and float on top of other +windows.</p> + +<p> An application usually consists of multiple activities that are loosely bound +to each other. Typically, one activity in an application is specified as the "main" activity, which +is presented to the user when launching the application for the first time. Each +activity can then start another activity in order to perform different actions. Each time a new +activity starts, the previous activity is stopped, but the system preserves the activity +in a stack (the "back stack"). When a new activity starts, it is pushed onto the back stack and +takes user focus. The back stack abides to the basic "last in, first out" queue mechanism, +so, when the user is done with the current activity and presses the BACK key, it +is popped from the stack (and destroyed) and the previous activity resumes. (The back stack is +discussed more in the <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks +and Back Stack</a> document.)</p> + +<p>When an activity is stopped because a new activity starts, it is notified of this change in state +through the activity's lifecycle callback methods. +There are several callback methods that an activity might receive, due to a change in its +state—whether the system is creating it, stopping it, resuming it, or destroying it—and +each callback provides you the opportunity to perform specific work that's +appropriate to that state change. For instance, when stopped, your activity should release any +large objects, such as network or database connections. When the activity resumes, you can +reacquire the necessary resources and resume actions that were interrupted. These state transitions +are all part of the activity lifecycle.</p> + +<p>The rest of this document discusses the basics of how to build and use an activity, +including a complete discussion of how the activity lifecycle works, so you can properly manage +the transition between various activity states.</p> + + + +<h2 id="Creating">Creating an Activity</h2> + +<p>To create an activity, you must create a subclass of {@link android.app.Activity} (or +an existing subclass of it). In your subclass, you need to implement callback methods that the +system calls when the activity transitions between various states of its lifecycle, such as when +the activity is being created, stopped, resumed, or destroyed. The two most important callback +methods are:</p> + +<dl> + <dt>{@link android.app.Activity#onCreate onCreate()}</dt> + <dd>You must implement this method. The system calls this when creating your + activity. Within your implementation, you should initialize the essential components of your +activity. + Most importantly, this is where you must call {@link android.app.Activity#setContentView + setContentView()} to define the layout for the activity's user interface.</dd> + <dt>{@link android.app.Activity#onPause onPause()}</dt> + <dd>The system calls this method as the first indication that the user is leaving your +activity (though it does not always mean the activity is being destroyed). This is usually where you +should commit any changes that should be persisted beyond the current user session (because +the user might not come back).</dd> +</dl> + +<p>There are several other lifecycle callback methods that you should use in order to provide a +fluid user experience between activities and handle unexpected interuptions that cause your activity +to be stopped and even destroyed. All of the lifecycle callback methods are discussed later, in +the section about <a href="#Lifecycle">Managing the Activity Lifecycle</a>.</p> + + + +<h3 id="UI">Implementing a user interface</h3> + +<p> The user interface for an activity is provided by a hierarchy of views—objects derived +from the {@link android.view.View} class. Each view controls a particular rectangular space +within the activity's window and can respond to user interaction. For example, a view might be a +button that initiates an action when the user touches it.</p> + +<p>Android provides a number of ready-made views that you can use to design and organize your +layout. "Widgets" are views that provide a visual (and interactive) elements for the screen, such +as a button, text field, checkbox, or just an image. "Layouts" are views derived from {@link +android.view.ViewGroup} that provide a unique layout model for its child views, such as a linear +layout, a grid layout, or relative layout. You can also subclass the {@link android.view.View} and +{@link android.view.ViewGroup} classes (or existing subclasses) to create your own widgets and +layouts and apply them to your activity layout.</p> + +<p>The most common way to define a layout using views is with an XML layout file saved in your +application resources. This way, you can maintain the design of your user interface separately from +the source code that defines the activity's behavior. You can set the layout as the UI for your +activity with {@link android.app.Activity#setContentView(int) setContentView()}, passing the +resource ID for the layout. However, you can also create new {@link android.view.View}s in your +activity code and build a view hierarchy by inserting new {@link +android.view.View}s into a {@link android.view.ViewGroup}, then use that layout by passing the root +{@link android.view.ViewGroup} to {@link android.app.Activity#setContentView(View) +setContentView()}.</p> + +<p>For information about creating a user interface, see the <a +href="{@docRoot}guide/topics/ui/index.html">User Interface</a> documentation.</p> + + + +<h3 id="Declaring">Declaring the activity in the manifest</h3> + +<p>You must declare your activity in the manifest file in order for it to +be accessible to the system. To decalare your activity, open your manifest file and add an <a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element +as a child of the <a +href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> +element. For example:</p> + +<pre> +<manifest ... > + <application ... > + <activity android:name=".ExampleActivity" /> + ... + </application ... > + ... +</manifest > +</pre> + +<p>There are several other attributes that you can include in this element, to define properties +such as the label for the activity, an icon for the activity, or a theme to style the activity's +UI. See the <a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element +reference for more information about available attributes.</p> + + +<h4>Using intent filters</h4> + +<p>An <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a> element can also specify various intent filters—using the <a +href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> element—in order to declare how other application components may +activate it.</p> + +<p>When you create a new application using the Android SDK tools, the stub activity +that's created for you automatically includes an intent filter that declares the activity +responds to the "main" action and should be placed in the "launcher" category. The intent filter +looks like this:</p> + +<pre> +<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +</pre> + +<p>The <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a> element specifies that this is the "main" entry point to the application. The <a +href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> element specifies that this activity should be listed in the +system's application launcher (to allow users to launch this activity).</p> + +<p>If you intend for your application to be self-contained and not allow other applications to +activate its activities, then you don't need any other intent filters. Only one activity should +have the "main" action and "launcher" category, as in the previous example. Activities that +you don't want to make available to other applications should have no intent filters and you can +start them yourself using explicit intents (as discussed in the following section).</p> + +<p>However, if you want your activity to respond to implicit intents that are delivered from +other applications (and your own), then you must define additional intent filters for your +activity. For each type of intent to which you want to respond, you must include an <a +href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> that includes an +<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a> element and, optionally, a <a +href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> element and/or a <a +href="{@docRoot}guide/topics/manifest/data-element.html">{@code +<data>}</a> element. These elements specify the type of intent to which your activity can +respond.</p> + +<p>For more information about how your activities can respond to intents, see the <a +href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a> +document.</p> + + + +<h2 id="StartingAnActivity">Starting an Activity</h2> + +<p>You can start another activity by calling {@link android.app.Activity#startActivity + startActivity()}, passing it an {@link android.content.Intent} that describes the activity you + want to start. The intent specifies either the exact activity you want to start or describes the + type of action you want to perform (and the system selects the appropriate activity for you, +which + can even be from a different application). An intent can also carry small amounts of data to be + used by the activity that is started.</p> + +<p>When working within your own application, you'll often need to simply launch a known activity. + You can do so by creating an intent that explicitly defines the activity you want to start, +using the class name. For example, here's how one activity starts another activity named {@code +SignInActivity}:</p> + +<pre> +Intent intent = new Intent(this, SignInActivity.class); +startActivity(intent); +</pre> + +<p>However, your application might also want to perform some action, such as send an email, text + message, or status update, using data from your activity. In this case, your application might + not have its own activities to perform such actions, so you can instead leverage the activities + provided by other applications on the device, which can perform the actions for you. This is where +intents are really valuable—you can create an intent that describes an action you want to +perform and the system + launches the appropriate activity from another application. If there are + multiple activities that can handle the intent, then the user can select which one to use. For + example, if you want to allow the user to send an email message, you can create the + following intent:</p> + +<pre> +Intent intent = new Intent(Intent.ACTION_SEND); +intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); +startActivity(intent); +</pre> + +<p>The {@link android.content.Intent#EXTRA_EMAIL} extra added to the intent is a string array of + email addresses to which the email should be sent. When an email application responds to this + intent, it reads the string array provided in the extra and places them in the "to" field of the + email composition form. In this situation, the email application's activity starts and when the + user is done, your activity resumes.</p> + + + + +<h3 id="StartingAnActivityForResult">Starting an activity for a result</h3> + +<p>Sometimes, you might want to receive a result from the activity that you start. In that case, + start the activity by calling {@link android.app.Activity#startActivityForResult + startActivityForResult()} (instead of {@link android.app.Activity#startActivity + startActivity()}). To then receive the result from the subsequent +activity, implement the {@link android.app.Activity#onActivityResult onActivityResult()} callback + method. When the subsequent activity is done, it returns a result in an {@link +android.content.Intent} to your {@link android.app.Activity#onActivityResult onActivityResult()} +method.</p> + +<p>For example, perhaps you want the user to pick one of their contacts, so your activity can +do something with the information in that contact. Here's how you can create such an intent and +handle the result:</p> + +<pre> +private void pickContact() { + // Create an intent to "pick" a contact, as defined by the content provider URI + Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); + startActivityForResult(intent, PICK_CONTACT_REQUEST); +} + +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // If the request went well (OK) and the request was PICK_CONTACT_REQUEST + if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { + // Perform a query to the contact's content provider for the contact's name + Cursor cursor = getContentResolver().query(data.getData(), + new String[] {Contacts.DISPLAY_NAME}, null, null, null); + if (cursor.moveToFirst()) { // True if the cursor is not empty + int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); + String name = cursor.getString(columnIndex); + // Do something with the selected contact's name... + } + } +} +</pre> + +<p>This example shows the basic logic you should use in your {@link +android.app.Activity#onActivityResult onActivityResult()} method in order to handle an +activity result. The first condition checks whether the request was successful—if it was, then +the {@code resultCode} will be {@link android.app.Activity#RESULT_OK}—and whether the request +to which this result is responding is known—in this case, the {@code requestCode} matches the +second parameter sent with {@link android.app.Activity#startActivityForResult +startActivityForResult()}. From there, the code handles the activity result by querying the +data returned in an {@link android.content.Intent} (the {@code data} parameter).</p> + +<p>What happens is, a {@link +android.content.ContentResolver} performs a query against a content provider, which returns a +{@link android.database.Cursor} that allows the queried data to be read. For more information, see +the <a +href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> document.</p> + +<p>For more information about using intents, see the <a +href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent +Filters</a> document.</p> + + +<h2 id="ShuttingDown">Shutting Down an Activity</h2> + +<p>You can shut down an activity by calling its {@link android.app.Activity#finish +finish()} method. You can also shut down a separate activity that you previously started by calling +{@link android.app.Activity#finishActivity finishActivity()}.</p> + +<p class="note"><strong>Note:</strong> In most cases, you should not explicitly finish an activity +using these methods. As discussed in the following section about the activity lifecycle, the +Android system manages the life of an activity for you, so you do not need to finish your own +activities. Calling these methods could adversely affect the expected user +experience and should only be used when you absolutely do not want the user to return to this +instance of the activity.</p> + + +<h2 id="Lifecycle">Managing the Activity Lifecycle</h2> + +<p>Managing the lifecycle of your activities by implementing callback methods is +crucial to developing a strong +and flexible application. The lifecycle of an activity is directly affected by its association with +other activities, its task and back stack.</p> + +<p>An activity can exist in essentially three states:</p> + +<dl> + <dt><i>Resumed</i></dt> + <dd>The activity is in the foreground of the screen and has user focus. (This state is +also sometimes referred to as "running".)</dd> + + <dt><i>Paused</i></dt> + <dd>Another activity is in the foreground and has focus, but this one is still visible. That is, +another activity is visible on top of this one and that activity is partially transparent or doesn't +cover the entire screen. A paused activity is completely alive (the {@link android.app.Activity} +object is retained in memory, it maintains all state and member information, and remains attached to +the window manager), but can be killed by the system in extremely low memory situations.</dd> + + <dt><i>Stopped</i></dt> + <dd>The activity is completely obscured by another activity (the activity is now in the +"background"). A stopped activity is also still alive (the {@link android.app.Activity} +object is retained in memory, it maintains all state and member information, but is <em>not</em> +attached to the window manager). However, it is no longer visible to the user and it +can be killed by the system when memory is needed elsewhere.</dd> +</dl> + +<p>If an activity is paused or stopped, the system can drop it from memory either by asking it to +finish (calling its {@link android.app.Activity#finish finish()} method), or simply killing its +process. When the activity is opened again (after being finished or killed), it must be created all +over.</p> + + + +<h3 id="ImplementingLifecycleCallbacks">Implementing the lifecycle callbacks</h3> + +<p>When an activity transitions into and out of the different states described above, it is notified +through various callback methods. All of the callback methods are hooks that you +can override to do appropriate work when the state of your activity changes. The following skeleton +activity includes each of the fundamental lifecycle methods:</p> + + +<pre> +public class ExampleActivity extends Activity { + @Override + public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // The activity is being created. + } + @Override + protected void {@link android.app.Activity#onStart onStart()} { + super.onStart(); + // The activity is about to become visible. + } + @Override + protected void {@link android.app.Activity#onResume onResume()} { + super.onResume(); + // The activity has become visible (it is now "resumed"). + } + @Override + protected void {@link android.app.Activity#onPause onPause()} { + super.onPause(); + // Another activity is taking focus (this activity is about to be "paused"). + } + @Override + protected void {@link android.app.Activity#onStop onStop()} { + super.onStop(); + // The activity is no longer visible (it is now "stopped") + } + @Override + protected void {@link android.app.Activity#onDestroy onDestroy()} { + super.onDestroy(); + // The activity is about to be destroyed. + } +} +</pre> + +<p class="note"><strong>Note:</strong> Your implementation of these lifecycle methods must +always call the superclass implementation before doing any work, as shown in the examples above.</p> + +<p>Taken together, these methods define the entire lifecycle of an activity. By implementing these +methods, you can monitor three nested loops in the activity lifecycle: </p> + +<ul> +<li>The <b>entire lifetime</b> of an activity happens between the call to {@link +android.app.Activity#onCreate onCreate()} and the call to {@link +android.app.Activity#onDestroy}. Your activity should perform setup of +"global" state (such as defining layout) in {@link android.app.Activity#onCreate onCreate()}, and +release all remaining resources in {@link android.app.Activity#onDestroy}. For example, if your +activity has a thread running in the background to download data from the network, it might create +that thread in {@link android.app.Activity#onCreate onCreate()} and then stop the thread in {@link +android.app.Activity#onDestroy}.</li> + +<li><p>The <b>visible lifetime</b> of an activity happens between the call to {@link +android.app.Activity#onStart onStart()} and the call to {@link +android.app.Activity#onStop onStop()}. During this time, the user can see the activity +on-screen and interact with it. For example, {@link android.app.Activity#onStop onStop()} is called +when a new activity starts and this one is no longer visible. Between these two methods, you can +maintain resources that are needed to show the activity to the user. For example, you can register a +{@link android.content.BroadcastReceiver} in {@link +android.app.Activity#onStart onStart()} to monitor changes that impact your UI, and unregister +it in {@link android.app.Activity#onStop onStop()} when the user can no longer see what you are +displaying. The system might call {@link android.app.Activity#onStart onStart()} and {@link +android.app.Activity#onStop onStop()} multiple times during the entire lifetime of the activity, as +the activity alternates between being visible and hidden to the user.</p></li> + +<li><p>The <b>foreground lifetime</b> of an activity happens between the call to {@link +android.app.Activity#onResume onResume()} and the call to {@link android.app.Activity#onPause +onPause()}. During this time, the activity is in front of all other activities on screen and has +user input focus. An activity can frequently transition in and out of the foreground—for +example, {@link android.app.Activity#onPause onPause()} is called when the device goes to sleep or +when a dialog appears. Because this state can transition often, the code in these two methods should +be fairly lightweight in order to avoid slow transitions that make the user wait.</p></li> +</ul> + +<p>Figure 1 illustrates these loops and the paths an activity might take between states. +The rectangles represent the callback methods you can implement to perform operations when +the activity transitions between states. <p> + +<img src="{@docRoot}images/activity_lifecycle.png" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> The activity lifecycle.</p> + +<p>The same lifecycle callback methods are listed in table 1, which describes each of the callback +methods in more detail and locates each one within the +activity's overall lifecycle, including whether the system can kill the activity after the +callback method completes.</p> + +<p class="table-caption"><strong>Table 1.</strong> A summary of the activity lifecycle's +callback methods.</p> + +<table border="2" width="85%" frame="hsides" rules="rows"> +<colgroup align="left" span="3"></colgroup> +<colgroup align="left"></colgroup> +<colgroup align="center"></colgroup> +<colgroup align="center"></colgroup> + +<thead> +<tr><th colspan="3">Method</th> <th>Description</th> <th>Killable after?</th> <th>Next</th></tr> +</thead> + +<tbody> +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td> + <td>Called when the activity is first created. + This is where you should do all of your normal static set up — + create views, bind data to lists, and so on. This method is passed + a Bundle object containing the activity's previous state, if that + state was captured (see <a href="#actstate">Saving Activity State</a>, + later). + <p>Always followed by {@code onStart()}.</p></td> + <td align="center">No</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td rowspan="5" style="border-left: none; border-right: none;"> </td> + <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart +onRestart()}</code></td> + <td>Called after the activity has been stopped, just prior to it being + started again. + <p>Always followed by {@code onStart()}</p></td> + <td align="center">No</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td> + <td>Called just before the activity becomes visible to the user. + <p>Followed by {@code onResume()} if the activity comes + to the foreground, or {@code onStop()} if it becomes hidden.</p></td> + <td align="center">No</td> + <td align="center">{@code onResume()} <br/>or<br/> {@code onStop()}</td> +</tr> + +<tr> + <td rowspan="2" style="border-left: none;"> </td> + <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td> + <td>Called just before the activity starts + interacting with the user. At this point the activity is at + the top of the activity stack, with user input going to it. + <p>Always followed by {@code onPause()}.</p></td> + <td align="center">No</td> + <td align="center">{@code onPause()}</td> +</tr> + +<tr> + <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td> + <td>Called when the system is about to start resuming another + activity. This method is typically used to commit unsaved changes to + persistent data, stop animations and other things that may be consuming + CPU, and so on. It should do whatever it does very quickly, because + the next activity will not be resumed until it returns. + <p>Followed either by {@code onResume()} if the activity + returns back to the front, or by {@code onStop()} if it becomes + invisible to the user.</td> + <td align="center"><strong style="color:#800000">Yes</strong></td> + <td align="center">{@code onResume()} <br/>or<br/> {@code onStop()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td> + <td>Called when the activity is no longer visible to the user. This + may happen because it is being destroyed, or because another activity + (either an existing one or a new one) has been resumed and is covering it. + <p>Followed either by {@code onRestart()} if + the activity is coming back to interact with the user, or by + {@code onDestroy()} if this activity is going away.</p></td> + <td align="center"><strong style="color:#800000">Yes</strong></td> + <td align="center">{@code onRestart()} <br/>or<br/> {@code onDestroy()}</td> +</tr> + +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy +onDestroy()}</code></td> + <td>Called before the activity is destroyed. This is the final call + that the activity will receive. It could be called either because the + activity is finishing (someone called <code>{@link android.app.Activity#finish + finish()}</code> on it), or because the system is temporarily destroying this + instance of the activity to save space. You can distinguish + between these two scenarios with the <code>{@link + android.app.Activity#isFinishing isFinishing()}</code> method.</td> + <td align="center"><strong style="color:#800000">Yes</strong></td> + <td align="center"><em>nothing</em></td> +</tr> +</tbody> +</table> + +<p>The column labeled "Killable after?" indicates whether or not the system can +kill the process hosting the activity at any time <em>after the method returns</em>, without +executing another line of the activity's code. Three methods are marked "yes": ({@link +android.app.Activity#onPause +onPause()}, {@link android.app.Activity#onStop onStop()}, and {@link android.app.Activity#onDestroy +onDestroy()}). Because {@link android.app.Activity#onPause onPause()} is the first +of the three, once the activity is created, {@link android.app.Activity#onPause onPause()} is the +last method that's guaranteed to be called before the process <em>can</em> be killed—if +the system must recover memory in an emergency, then {@link +android.app.Activity#onStop onStop()} and {@link android.app.Activity#onDestroy onDestroy()} might +not be called. Therefore, you should use {@link android.app.Activity#onPause onPause()} to write +crucial persistent data (such as user edits) to storage. However, you should be selective about +what information must be retained during {@link android.app.Activity#onPause onPause()}, because any +blocking procedures in this method block the transition to the next activity and slow the user +experience.</p> + +<p> Methods that are marked "No" in the <b>Killable</b> column protect the process hosting the +activity from being killed from the moment they are called. Thus, an activity is killable +from the time {@link android.app.Activity#onPause onPause()} returns to the time +{@link android.app.Activity#onResume onResume()} is called. It will not again be killable until +{@link android.app.Activity#onPause onPause()} is again called and returns. </p> + +<p class="note"><strong>Note:</strong> An activity that's not technically "killable" by this +definition in table 1 might still be killed by the system—but that would happen only in +extreme circumstances when there is no other recourse. When an activity might be killed is +discussed more in the <a +href="{@docRoot}guide/topics/fundamentals/processes-and-threading.html">Processes and +Threading</a> document.</p> + + +<h3 id="SavingActivityState">Saving activity state</h3> + +<p>The introduction to <a href="Lifecycle">Managing the Activity Lifecycle</a> briefly mentions that +when an activity is paused or stopped, the state of the activity is retained. This is true because +the {@link android.app.Activity} object is still held in memory when it is paused or +stopped—all information about its members and current state is still alive. Thus, any changes +the user made within the activity are retained in memory, so that when the activity returns to the +foreground (when it "resumes"), those changes are still there.</p> + +<div class="figure" style="width:615px"> +<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" /> +<p class="img-caption"><strong>Figure 2.</strong> The two ways in which an activity returns to user +focus with its state intact: either the activity is stopped, then resumed and the activity state +remains intact (left), or the activity is destroyed, then recreated and the activity must restore +the previous activity state (right).</p> +</div> + +<p>However, when the system destroys an activity in order to recover memory, the {@link +android.app.Activity} object is destroyed, so the system cannot simply resume it with its state +intact. Instead, the system must recreate the {@link android.app.Activity} object if the user +navigates back to it. Yet, the user is unaware +that the system destroyed the activity and recreated it and, thus, probably +expects the activity to be exactly as it was. In this situation, you can ensure that +important information about the activity state is preserved by implementing an additional +callback method that allows you to save information about the state of your activity and then +restore it when the the system recreates the activity.</p> + +<p>The callback method in which you can save information about the current state of your activity is +{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}. The system calls this method +before making the activity vulnerable to being destroyed and passes it +a {@link android.os.Bundle} object. The {@link android.os.Bundle} is where you can store +state information about the activity as name-value pairs, using methods such as {@link +android.os.Bundle#putString putString()}. Then, if the system kills your activity's +process and the user navigates back to your activity, the system passes the {@link +android.os.Bundle} to {@link android.app.Activity#onCreate onCreate()} so you can restore the +activity state you saved during {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()}. If there is no state information to restore, then the {@link +android.os.Bundle} passed to {@link android.app.Activity#onCreate onCreate()} is null.</p> + +<p class="note"><strong>Note:</strong> There's no guarantee that {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} will be called before your +activity is destroyed, because there are cases in which it won't be necessary to save the state +(such as when the user leaves your activity using the BACK key, because the user is explicitly +closing the activity). If the method is called, it is always called before {@link +android.app.Activity#onStop onStop()} and possibly before {@link android.app.Activity#onPause +onPause()}.</p> + +<p>However, even if you do nothing and do not implement {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()}, some of the activity state is +restored by the {@link android.app.Activity} class's default implementation of {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()}. Specifically, the default +implementation calls {@link +android.view.View#onSaveInstanceState onSaveInstanceState()} for every {@link android.view.View} +in the layout, which allows each view to provide information about itself +that should be saved. Almost every widget in the Android framework implements this method as +appropriate, such that any visible changes to the UI are automatically saved and restored when your +activity is recreated. For example, the {@link android.widget.EditText} widget saves any text +entered by the user and the {@link android.widget.CheckBox} widget saves whether it's checked or +not. The only work required by you is to provide a unique ID (with the <a +href="{@docRoot}guide/topics/resources/layout-resource.html#idvalue">{@code android:id}</a> +attribute) for each widget you want to save its state. If a widget does not have an ID, then it +cannot save its state.</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<p>You can also explicitly stop a view in your layout from saving its state by setting the +{@link android.R.attr#saveEnabled android:saveEnabled} attribute to {@code "false"} or by calling +the {@link android.view.View#setSaveEnabled setSaveEnabled()} method. Usually, you should not +disable this, but you might if you want to restore the state of the activity UI differently.</p> +</div> +</div> + +<p>Although the default implementation of {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} saves useful information about +your activity's UI, you still might need to override it to save additional information. +For example, you might need to save member values that changed during the activity's life (which +might correlate to values restored in the UI, but the members that hold those UI values are not +restored, by default).</p> + +<p>Because the default implementation of {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} helps save the state of the UI, if +you override the method in order to save additional state information, you should always call the +superclass implementation of {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} +before doing any work.</p> + +<p class="note"><strong>Note:</strong> Because {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} is not guaranteed +to be called, you should use it only to record the transient state of the activity (the state of +the UI)—you should never use it to store persistent data. Instead, you should use {@link +android.app.Activity#onPause onPause()} to store persistent data (such as data that should be saved +to a database) when the user leaves the activity.</p> + +<p>A good way to test your application's ability to restore its state is to simply rotate the +device so that the screen orientation changes. When the screen orientation changes, the system +destroys and recreates the activity in order to apply alternative resources that might be available +for the new orientation. For this reason alone, it's very important that your activity +completely restores its state when it is recreated, because users regularly rotate the screen while +using applications.</p> + + +<h3 id="ConfigurationChanges">Handling configuration changes</h3> + +<p>Some device configurations can change during runtime (such as screen orientation, keyboard +availability, and language). When such a change occurs, Android restarts the running Activity +({@link android.app.Activity#onDestroy} is called, followed immediately by {@link +android.app.Activity#onCreate onCreate()}). The restart behavior is +designed to help your application adapt to new configurations by automatically reloading your +application with alternative resources that you've provided. If you design your activity to +properly handle this event, it will be more resilient to unexpected events in the activity +lifecycle.</p> + +<p>The best way to handle a configuration change, such as a change in the screen orientation, is + to simply preserve the state of your application using {@link + android.app.Activity#onSaveInstanceState onSaveInstanceState()} and {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (or {@link +android.app.Activity#onCreate onCreate()}), as discussed in the previous section.</p> + +<p>For a detailed discussion about configuration changes that happen at runtime and how you should +handle them, read <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling +Runtime Changes</a>.</p> + + + +<h3 id="CoordinatingActivities">Coordinating activities</h3> + + <p>When one activity starts another, they both experience lifecycle transitions. The first activity +pauses and stops (though, it won't stop if it's still visible in the background), while the other +activity is created. In case these activities share data saved to disc or elsewhere, it's important +to understand that the first activity is not completely stopped before the second one is created. +Rather, the process of starting the second one overlaps with the process of stopping the first +one.</p> + +<p>The order of lifecycle callbacks is well defined, particularly when the two activities are in the +same process and one is starting the other. Here's the order of operations that occur when Activity +A starts Acivity B: </p> + +<ol> +<li>Activity A's {@link android.app.Activity#onPause onPause()} method executes.</li> + +<li>Activity B's {@link android.app.Activity#onCreate onCreate()}, {@link +android.app.Activity#onStart onStart()}, and {@link android.app.Activity#onResume onResume()} +methods execute in sequence. (Activity B now has user focus.)</li> + +<li>Then, if Activity A is no longer visible on screen, its {@link +android.app.Activity#onStop onStop()} method executes.</li> +</ol> + + <p>This predictable sequence of lifecycle callbacks allows you to manage the transition of +information from one activity to another. For example, if you must write to a database when the +first activity stops so that the following activity can read it, then you should write to the +database during {@link android.app.Activity#onPause onPause()} instead of during {@link +android.app.Activity#onStop onStop()}.</p> + + +<h2>Beginner's Path</h2> + +<p>For more information about how Android maintains a history of activities and +enables user multitasking, continue with the <b><a +href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back +Stack</a></b> document.</p> diff --git a/docs/html/guide/topics/fundamentals/bound-services.jd b/docs/html/guide/topics/fundamentals/bound-services.jd new file mode 100644 index 0000000..e5d626c --- /dev/null +++ b/docs/html/guide/topics/fundamentals/bound-services.jd @@ -0,0 +1,675 @@ +page.title=Bound Services +parent.title=Services +parent.link=services.html +@jd:body + + +<div id="qv-wrapper"> +<ol id="qv"> +<h2>Quickview</h2> +<ul> + <li>A bound service allows other components to bind to it, in order to interact with it and +perform interprocess communication</li> + <li>A bound service is destroyed once all clients unbind, unless the service was also started</li> +</ul> +<h2>In this document</h2> +<ol> + <li><a href="#Basics">The Basics</a></li> + <li><a href="#Creating">Creating a Bound Service</a> + <ol> + <li><a href="#Binder">Extending the Binder class</a></li> + <li><a href="#Messenger">Using a Messenger</a></li> + </ol> + </li> + <li><a href="#Binding">Binding to a Service</a></li> + <li><a href="#Lifecycle">Managing the Lifecycle of a Bound Service</a></li> +</ol> + +<h2>Key classes</h2> +<ol> + <li>{@link android.app.Service}</li> + <li>{@link android.content.ServiceConnection}</li> + <li>{@link android.os.IBinder}</li> +</ol> + +<h2>Samples</h2> +<ol> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code + RemoteService}</a></li> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code + LocalService}</a></li> +</ol> + +<h2>See also</h2> +<ol> + <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li> +</ol> +</div> + + +<p>A bound service is the server in a client-server interface. A bound service allows components +(such as activities) to bind to the service, send requests, receive responses, and even perform +interprocess communication (IPC). A bound service typically lives only while it serves another +application component and does not run in the background indefinitely.</p> + +<p>This document shows you how to create a bound service, including how to bind +to the service from other application components. However, you should also refer to the <a +href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> document for additional +information about services in general, such as how to deliver notifications from a service, set +the service to run in the foreground, and more.</p> + + +<h2 id="Basics">The Basics</h2> + +<p>A bound service is an implementation of the {@link android.app.Service} class that allows +other applications to bind to it and interact with it. To provide binding for a +service, you must implement the {@link android.app.Service#onBind onBind()} callback method. This +method returns an {@link android.os.IBinder} object that defines the programming interface that +clients can use to interact with the service.</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>Binding to a Started Service</h3> + +<p>As discussed in the <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> +document, you can create a service that is both started and bound. That is, the service can be +started by calling {@link android.content.Context#startService startService()}, which allows the +service to run indefinitely, and also allow a client to bind to the service by calling {@link +android.content.Context#bindService bindService()}. + <p>If you do allow your service to be started and bound, then when the service has been +started, the system does <em>not</em> destroy the service when all clients unbind. Instead, you must +explicitly stop the service, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link +android.content.Context#stopService stopService()}.</p> + +<p>Although you should usually implement either {@link android.app.Service#onBind onBind()} +<em>or</em> {@link android.app.Service#onStartCommand onStartCommand()}, it's sometimes necessary to +implement both. For example, a music player might find it useful to allow its service to run +indefinitely and also provide binding. This way, an activity can start the service to play some +music and the music continues to play even if the user leaves the application. Then, when the user +returns to the application, the activity can bind to the service to regain control of playback.</p> + +<p>Be sure to read the section about <a href="#Lifecycle">Managing the Lifecycle of a Bound +Service</a>, for more information about the service lifecycle when adding binding to a +started service.</p> +</div> +</div> + +<p>A client can bind to the service by calling {@link android.content.Context#bindService +bindService()}. When it does, it must provide an implementation of {@link +android.content.ServiceConnection}, which monitors the connection with the service. The {@link +android.content.Context#bindService bindService()} method returns immediately without a value, but +when the Android system creates the connection between the +client and service, it calls {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} on the {@link +android.content.ServiceConnection}, to deliver the {@link android.os.IBinder} that +the client can use to communicate with the service.</p> + +<p>Multiple clients can connect to the service at once. However, the system calls your service's +{@link android.app.Service#onBind onBind()} method to retrieve the {@link android.os.IBinder} only +when the first client binds. The system then delivers the same {@link android.os.IBinder} to any +additional clients that bind, without calling {@link android.app.Service#onBind onBind()} again.</p> + +<p>When the last client unbinds from the service, the system destroys the service (unless the +service was also started by {@link android.content.Context#startService startService()}).</p> + +<p>When you implement your bound service, the most important part is defining the interface +that your {@link android.app.Service#onBind onBind()} callback method returns. There are a few +different ways you can define your service's {@link android.os.IBinder} interface and the following +section discusses each technique.</p> + + + +<h2 id="Creating">Creating a Bound Service</h2> + +<p>When creating a service that provides binding, you must provide an {@link android.os.IBinder} +that provides the programming interface that clients can use to interact with the service. There +are three ways you can define the interface:</p> + +<dl> + <dt><a href="#Binder">Extending the Binder class</a></dt> + <dd>If your service is private to your own application and runs in the same process as the client +(which is common), you should create your interface by extending the {@link android.os.Binder} class +and returning an instance of it from +{@link android.app.Service#onBind onBind()}. The client receives the {@link android.os.Binder} and +can use it to directly access public methods available in either the {@link android.os.Binder} +implementation or even the {@link android.app.Service}. + <p>This is the preferred technique when your service is merely a background worker for your own +application. The only reason you would not create your interface this way is because +your service is used by other applications or across separate processes.</dd> + + <dt><a href="#Messenger">Using a Messenger</a></dt> + <dd>If you need your interface to work across different processes, you can create +an interface for the service with a {@link android.os.Messenger}. In this manner, the service +defines a {@link android.os.Handler} that responds to different types of {@link +android.os.Message} objects. This {@link android.os.Handler} +is the basis for a {@link android.os.Messenger} that can then share an {@link android.os.IBinder} +with the client, allowing the client to send commands to the service using {@link +android.os.Message} objects. Additionally, the client can define a {@link android.os.Messenger} of +its own so the service can send messages back. + <p>This is the simplest way to perform interprocess communication (IPC), because the {@link +android.os.Messenger} queues all requests into a single thread so that you don't have to design +your service to be thread-safe.</p> + </dd> + + <dt>Using AIDL</dt> + <dd>AIDL (Android Interface Definition Language) performs all the work to decompose objects into +primitives that the operating system can understand and marshall them across processes to perform +IPC. The previous technique, using a {@link android.os.Messenger}, is actually based on AIDL as +its underlying structure. As mentioned above, the {@link android.os.Messenger} creates a queue of +all the client requests in a single thread, so the service receives requests one at a time. If, +however, you want your service to handle multiple requests simultaneously, then you can use AIDL +directly. In this case, your service must be capable of multi-threading and be built thread-safe. + <p>To use AIDL directly, you must +create an {@code .aidl} file that defines the programming interface. The Android SDK tools use +this file to generate an abstract class that implements the interface and handles IPC, which you +can then extend within your service.</p> + </dd> +</dl> + + <p class="note"><strong>Note:</strong> Most applications <strong>should not</strong> use AIDL to +create a bound service, because it may require multithreading capabilities and +can result in a more complicated implementation. As such, AIDL is not suitable for most applications +and this document does not discuss how to use it for your service. If you're certain that you need +to use AIDL directly, see the <a href="{@docRoot}guide/topics/advanced/aidl.html">AIDL</a> +document.</p> + + + + +<h3 id="Binder">Extending the Binder class</h3> + +<p>If your service is used only by the local application and does not need to work across processes, +then you can implement your own {@link android.os.Binder} class that provides your client direct +access to public methods in the service.</p> + +<p class="note"><strong>Note:</strong> This works only if the client and service are in the same +application and process, which is most common. For example, this would work well for a music +application that needs to bind an activity to its own service that's playing music in the +background.</p> + +<p>Here's how to set it up:</p> +<ol> + <li>In your service, create an instance of {@link android.os.Binder} that either: + <ul> + <li>contains public methods that the client can call</li> + <li>returns the current {@link android.app.Service} instance, which has public methods the +client can call</li> + <li>or, returns an instance of another class hosted by the service with public methods the +client can call</li> + </ul> + <li>Return this instance of {@link android.os.Binder} from the {@link +android.app.Service#onBind onBind()} callback method.</li> + <li>In the client, receive the {@link android.os.Binder} from the {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method and +make calls to the bound service using the methods provided.</li> +</ol> + +<p class="note"><strong>Note:</strong> The reason the service and client must be in the same +application is so the client can cast the returned object and properly call its APIs. The service +and client must also be in the same process, because this technique does not perform any +marshalling across processes.</p> + +<p>For example, here's a service that provides clients access to methods in the service through +a {@link android.os.Binder} implementation:</p> + +<pre> +public class LocalService extends Service { + // Binder given to clients + private final IBinder mBinder = new LocalBinder(); + // Random number generator + private final Random mGenerator = new Random(); + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + LocalService getService() { + // Return this instance of LocalService so clients can call public methods + return LocalService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** method for clients */ + public int getRandomNumber() { + return mGenerator.nextInt(100); + } +} +</pre> + +<p>The {@code LocalBinder} provides the {@code getService()} method for clients to retrieve the +current instance of {@code LocalService}. This allows clients to call public methods in the +service. For example, clients can call {@code getRandomNumber()} from the service.</p> + +<p>Here's an activity that binds to {@code LocalService} and calls {@code getRandomNumber()} +when a button is clicked:</p> + +<pre> +public class BindingActivity extends Activity { + LocalService mService; + boolean mBound = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to LocalService + Intent intent = new Intent(this, LocalService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } + + /** Called when a button is clicked (the button in the layout file attaches to + * this method with the android:onClick attribute) */ + public void onButtonClick(View v) { + if (mBound) { + // Call a method from the LocalService. + // However, if this call were something that might hang, then this request should + // occur in a separate thread to avoid slowing down the activity performance. + int num = mService.getRandomNumber(); + Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); + } + } + + /** Defines callbacks for service binding, passed to bindService() */ + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mBound = false; + } + }; +} +</pre> + +<p>The above sample shows how the client binds to the service using an implementation of +{@link android.content.ServiceConnection} and the {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback. The next +section provides more information about this process of binding to the service.</p> + +<p class="note"><strong>Note:</strong> The example above doesn't explicitly unbind from the service, +but all clients should unbind at an appropriate time (such as when the activity pauses).</p> + +<p>For more sample code, see the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code +LocalService.java}</a> class and the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code +LocalServiceActivities.java}</a> class in <a +href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p> + + + + + +<h3 id="Messenger">Using a Messenger</h3> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h4>Compared to AIDL</h4> + <p>When you need to perform IPC, using a {@link android.os.Messenger} for your interface is +simpler than implementing it with AIDL, because {@link android.os.Messenger} queues +all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the +service, which must then handle multi-threading.</p> + <p>For most applications, the service doesn't need to perform multi-threading, so using a {@link +android.os.Messenger} allows the service to handle one call at a time. If it's important +that your service be multi-threaded, then you should use <a +href="{@docRoot}guide/topics/advanced/aidl.html">AIDL</a> to define your interface.</p> +</div> +</div> + +<p>If you need your service to communicate with remote processes, then you can use a +{@link android.os.Messenger} to provide the interface for your service. This technique allows +you to perform interprocess communication (IPC) without the need to use AIDL.</p> + +<p>Here's a summary of how to use a {@link android.os.Messenger}:</p> + +<ul> + <li>The service implements a {@link android.os.Handler} that receives a callback for each +call from a client.</li> + <li>The {@link android.os.Handler} is used to create a {@link android.os.Messenger} object +(which is a reference to the {@link android.os.Handler}).</li> + <li>The {@link android.os.Messenger} creates an {@link android.os.IBinder} that the service +returns to clients from {@link android.app.Service#onBind onBind()}.</li> + <li>Clients use the {@link android.os.IBinder} to instantiate the {@link android.os.Messenger} +(that references the service's {@link android.os.Handler}), which the client uses to send +{@link android.os.Message} objects to the service.</li> + <li>The service receives each {@link android.os.Message} in its {@link +android.os.Handler}—specifically, in the {@link android.os.Handler#handleMessage +handleMessage()} method.</li> +</ul> + + +<p>In this way, there are no "methods" for the client to call on the service. Instead, the +client delivers "messages" ({@link android.os.Message} objects) that the service receives in +its {@link android.os.Handler}.</p> + +<p>Here's a simple example service that uses a {@link android.os.Messenger} interface:</p> + +<pre> +public class MessengerService extends Service { + /** Command to the service to display a message */ + static final int MSG_SAY_HELLO = 1; + + /** + * Handler of incoming messages from clients. + */ + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SAY_HELLO: + Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Target we publish for clients to send messages to IncomingHandler. + */ + final Messenger mMessenger = new Messenger(new IncomingHandler()); + + /** + * When binding to the service, we return an interface to our messenger + * for sending messages to the service. + */ + @Override + public IBinder onBind(Intent intent) { + Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); + return mMessenger.getBinder(); + } +} +</pre> + +<p>Notice that the {@link android.os.Handler#handleMessage handleMessage()} method in the +{@link android.os.Handler} is where the service receives the incoming {@link android.os.Message} +and decides what to do, based on the {@link android.os.Message#what} member.</p> + +<p>All that a client needs to do is create a {@link android.os.Messenger} based on the {@link +android.os.IBinder} returned by the service and send a message using {@link +android.os.Messenger#send send()}. For example, here's a simple activity that binds to the +service and delivers the {@code MSG_SAY_HELLO} message to the service:</p> + +<pre> +public class ActivityMessenger extends Activity { + /** Messenger for communicating with the service. */ + Messenger mService = null; + + /** Flag indicating whether we have called bind on the service. */ + boolean mBound; + + /** + * Class for interacting with the main interface of the service. + */ + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the object we can use to + // interact with the service. We are communicating with the + // service using a Messenger, so here we get a client-side + // representation of that from the raw IBinder object. + mService = new Messenger(service); + mBound = true; + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + mService = null; + mBound = false; + } + }; + + public void sayHello(View v) { + if (!mBound) return; + // Create and send a message to the service, using a supported 'what' value + Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); + try { + mService.send(msg); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to the service + bindService(new Intent(this, MessengerService.class), mConnection, + Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } +} +</pre> + +<p>Notice that this example does not show how the service can respond to the client. If you want the +service to respond, then you need to also create a {@link android.os.Messenger} in the client. Then +when the client receives the {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} callback, it sends a {@link android.os.Message} to the service that includes +the client's {@link android.os.Messenger} in the {@link android.os.Message#replyTo} parameter +of the {@link android.os.Messenger#send send()} method.</p> + +<p>You can see an example of how to provide two-way messaging in the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code +MessengerService.java}</a> (service) and <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code +MessengerServiceActivities.java}</a> (client) samples.</p> + + + + + +<h2 id="Binding">Binding to a Service</h2> + +<p>Application components (clients) can bind to a service by calling +{@link android.content.Context#bindService bindService()}. The Android +system then calls the service's {@link android.app.Service#onBind +onBind()} method, which returns an {@link android.os.IBinder} for interacting with the service.</p> + +<p>The binding is asynchronous. {@link android.content.Context#bindService +bindService()} returns immediately and does <em>not</em> return the {@link android.os.IBinder} to +the client. To receive the {@link android.os.IBinder}, the client must create an instance of {@link +android.content.ServiceConnection} and pass it to {@link android.content.Context#bindService +bindService()}. The {@link android.content.ServiceConnection} includes a callback method that the +system calls to deliver the {@link android.os.IBinder}.</p> + +<p class="note"><strong>Note:</strong> Only activities, services, and content providers can bind +to a service—you <strong>cannot</strong> bind to a service from a broadcast receiver.</p> + +<p>So, to bind to a service from your client, you must: </p> +<ol> + <li>Implement {@link android.content.ServiceConnection}. + <p>Your implementation must override two callback methods:</p> + <dl> + <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt> + <dd>The system calls this to deliver the {@link android.os.IBinder} returned by +the service's {@link android.app.Service#onBind onBind()} method.</dd> + <dt>{@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()}</dt> + <dd>The Android system calls this when the connection to the service is unexpectedly +lost, such as when the service has crashed or has been killed. This is <em>not</em> called when the +client unbinds.</dd> + </dl> + </li> + <li>Call {@link +android.content.Context#bindService bindService()}, passing the {@link +android.content.ServiceConnection} implementation. </li> + <li>When the system calls your {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} callback method, you can begin making calls to the service, using +the methods defined by the interface.</li> + <li>To disconnect from the service, call {@link +android.content.Context#unbindService unbindService()}. + <p>When your client is destroyed, it will unbind from the service, but you should always unbind +when you're done interacting with the service or when your activity pauses so that the service can +shutdown while its not being used. (Appropriate times to bind and unbind is discussed +more below.)</p> + </li> +</ol> + +<p>For example, the following snippet connects the client to the service created above by +<a href="#Binder">extending the Binder class</a>, so all it must do is cast the returned +{@link android.os.IBinder} to the {@code LocalService} class and request the {@code +LocalService} instance:</p> + +<pre> +LocalService mService; +private ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + // Because we have bound to an explicit + // service that is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + // Called when the connection with the service disconnects unexpectedly + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "onServiceDisconnected"); + mBound = false; + } +}; +</pre> + +<p>With this {@link android.content.ServiceConnection}, the client can bind to a service by passing +this it to {@link android.content.Context#bindService bindService()}. For example:</p> + +<pre> +Intent intent = new Intent(this, LocalService.class); +bindService(intent, mConnection, Context.BIND_AUTO_CREATE); +</pre> + +<ul> + <li>The first parameter of {@link android.content.Context#bindService bindService()} is an +{@link android.content.Intent} that explicitly names the service to bind (thought the intent +could be implicit).</li> +<li>The second parameter is the {@link android.content.ServiceConnection} object.</li> +<li>The third parameter is a flag indicating options for the binding. It should usually be {@link +android.content.Context#BIND_AUTO_CREATE} in order to create the service if its not already alive. +Other possible values are {@link android.content.Context#BIND_DEBUG_UNBIND} +and {@link android.content.Context#BIND_NOT_FOREGROUND}, or {@code 0} for none.</li> +</ul> + + +<h3>Additional notes</h3> + +<p>Here are some important notes about binding to a service:</p> +<ul> + <li>You should always trap {@link android.os.DeadObjectException} exceptions, which are thrown +when the connection has broken. This is the only exception thrown by remote methods.</li> + <li>Objects are reference counted across processes. </li> + <li>You should usually pair the binding and unbinding during +matching bring-up and tear-down moments of the client's lifecycle. For example: + <ul> + <li>If you only need to interact with the service while your activity is visible, you +should bind during {@link android.app.Activity#onStart onStart()} and unbind during {@link +android.app.Activity#onStop onStop()}.</li> + <li>If you want your activity to receive responses even while it is stopped in the +background, then you can bind during {@link android.app.Activity#onCreate onCreate()} and unbind +during {@link android.app.Activity#onDestroy onDestroy()}. Beware that this implies that your +activity needs to use the service the entire time it's running (even in the background), so if +the service is in another process, then you increase the weight of the process and it becomes +more likely that the system will kill it.</li> + </ul> + <p class="note"><strong>Note:</strong> You should usually <strong>not</strong> bind and unbind +during your activity's {@link android.app.Activity#onResume onResume()} and {@link +android.app.Activity#onPause onPause()}, because these callbacks occur at every lifecycle transition +and you should keep the processing that occurs at these transitions to a minimum. Also, if +multiple activities in your application bind to the same service and there is a transition between +two of those activities, the service may be destroyed and recreated as the current activity unbinds +(during pause) before the next one binds (during resume). (This activity transition for how +activities coordinate their lifecycles is described in the <a +href="{@docRoot}guide/topics/fundamentals/activities.html#CoordinatingActivities">Activities</a> +document.)</p> +</ul> + +<p>For more sample code, showing how to bind to a service, see the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code +RemoteService.java}</a> class in <a +href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p> + + + + + +<h2 id="Lifecycle">Managing the Lifecycle of a Bound Service</h2> + +<div class="figure" style="width:588px"> +<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> The lifecycle for a service that is started +and also allows binding.</p> +</div> + +<p>When a service is unbound from all clients, the Android system destroys it (unless it was also +started with {@link android.app.Service#onStartCommand onStartCommand()}). As such, you don't have +to manage the lifecycle of your service if it's purely a bound +service—the Android system manages it for you based on whether it is bound to any clients.</p> + +<p>However, if you choose to implement the {@link android.app.Service#onStartCommand +onStartCommand()} callback method, then you must explicitly stop the service, because the +service is now considered to be <em>started</em>. In this case, the service runs until the service +stops itself with {@link android.app.Service#stopSelf()} or another component calls {@link +android.content.Context#stopService stopService()}, regardless of whether it is bound to any +clients.</p> + +<p>Additionally, if your service is started and accepts binding, then when the system calls +your {@link android.app.Service#onUnbind onUnbind()} method, you can optionally return +{@code true} if you would like to receive a call to {@link android.app.Service#onRebind +onRebind()} the next time a client binds to the service (instead of receiving a call to {@link +android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind +onRebind()} returns void, but the client still receives the {@link android.os.IBinder} in its +{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback. +Below, figure 1 illustrates the logic for this kind of lifecycle.</p> + +<p>For more information about the lifecycle of an started service, see the <a +href="{@docRoot}guide/topics/fundamentals/services.html#Lifecycle">Services</a> document.</p> + + + + diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd new file mode 100644 index 0000000..9eceef1 --- /dev/null +++ b/docs/html/guide/topics/fundamentals/fragments.jd @@ -0,0 +1,815 @@ +page.title=Fragments +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>Quickview</h2> + <ul> + <li>Fragments decompose application functionality and UI into reusable modules</li> + <li>Add multiple fragments to a screen to avoid switching activities</li> + <li>Fragments have their own lifecycle, state, and back stack</li> + <li>Fragments require API Level "Honeycomb" or greater</li> + </ul> + + <h2>In this document</h2> + <ol> + <li><a href="#Design">Design Philosophy</a></li> + <li><a href="#Creating">Creating a Fragment</a> + <ol> + <li><a href="#UI">Adding a user interface</a></li> + <li><a href="#Adding">Adding a fragment to an activity</a></li> + </ol> + </li> + <li><a href="#Managing">Managing Fragments</a></li> + <li><a href="#Transactions">Performing Fragment Transactions</a></li> + <li><a href="#CommunicatingWithActivity">Communicating with the Activity</a> + <ol> + <li><a href="#EventCallbacks">Creating event callbacks to the activity</a></li> + <li><a href="#ActionBar">Adding items to the Action Bar</a></li> + </ol> + </li> + <li><a href="#Lifecycle">Handling the Fragment Lifecycle</a> + <ol> + <li><a href="#CoordinadingWithActivity">Coordinating with the activity lifecycle</a></li> + </ol> + </li> + <li><a href="#Example">Example</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.Fragment}</li> + <li>{@link android.app.FragmentManager}</li> + <li>{@link android.app.FragmentTransaction}</li> + </ol> + + <h2>Related samples</h2> + <ol> + <li><a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">ApiDemos</a></li> + </ol> +</div> +</div> + +<p>A {@link android.app.Fragment} represents a behavior or a portion of user interface in an +{@link android.app.Activity}. You can combine multiple fragments in a single activity to build a +multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a +modular section of an activity, which has its own lifecycle, receives its own input events, and +which you can add or remove while the activity is running.</p> + +<p>A fragment must always be embedded in an activity and the fragment's lifecycle is directly +affected by the host activity's lifecycle. For example, when the activity is paused, so are all +fragments in it, and when the activity is destroyed, so are all fragments. However, while an +activity is running (it is in the <em>resumed</em> <a +href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">lifecycle state</a>), you can +manipulate each fragment independently, such as add or remove them. When you perform such a +fragment transaction, you can also add it to a back stack that's managed by the +activity—each back stack entry in the activity is a record of the fragment transaction that +occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), +by pressing the BACK key.</p> + +<p>When you add a fragment as a part of your activity layout, it lives in a {@link +android.view.ViewGroup} inside the activity's view hierarchy and defines its own layout of views. +You can insert a fragment into your activity layout by declaring the fragment in the activity's +layout file, as a {@code <fragment>} element, or from your application code by adding it to an +existing {@link android.view.ViewGroup}. However, a fragment is not required to be a part of the +activity layout; you may also use a fragment as an invisible worker for the activity.</p> + +<p>This document describes how to build your application to use fragments, including +how fragments can maintain their state when added to the activity's back stack, share +events with the activity and other fragments in the activity, contribute to the activity's action +bar, and more.</p> + + +<h2 id="Design">Design Philosophy</h2> + +<p>Android introduced fragments in Android 3.0 (API Level "Honeycomb"), primarily to support more +dynamic and flexible UI designs on large screens, such as tablets. Because a +tablet's screen is much larger than that of a mobile phone, there's more room to combine and +interchange UI components. Fragments allow such designs without the need for you to manage complex +changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able +to modify the activity's appearance at runtime and preserve those changes in a back stack +that's managed by the activity.</p> + +<p>For example, a news application can use one fragment to show a list of articles on the +left and another fragment to display an article on the right—both fragments appear in one +activity, side by side, and each fragment has its own set of lifecycle callback methods and handle +their own user input events. Thus, instead of using one activity to select an article and another +activity to read the article, the user can select an article and read it all within the same +activity, as illustrated in figure 1.</p> + +<img src="{@docRoot}images/fundamentals/fragments.png" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> An example of how two UI modules that are +typically separated into two activities can be combined into one activity, using fragments.</p> + + +<p>A fragment should be a modular and reusable component in your application. That is, because the +fragment defines its own layout and its own behavior using its own lifecycle callbacks, you +can include one fragment in multiple activities. This is especially important because it allows you +to adapt your user experience to different screen sizes. For instance, you might include multiple +fragments in an activity only when the screen size is sufficiently large, and, when it is not, +launch separate activities that use different fragments.</p> + +<p>For example—to continue with the news application example—the application can embed +two +fragments in <em>Activity A</em>, when running on an extra large screen (a tablet, for example). +However, on a normal-sized screen (a phone, for example), +there's not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for +the list of articles, and when the user selects an article, it starts <em>Activity B</em>, which +includes the fragment to read the article. Thus, the application supports both design patterns +suggested in figure 1.</p> + + + +<h2 id="Creating">Creating a Fragment</h2> + +<div class="figure" style="width:314px"> +<img src="{@docRoot}images/fragment_lifecycle.png" alt="" /> +<p class="img-caption"><strong>Figure 2.</strong> The lifecycle of a fragment (while its +activity is running).</p> +</div> + +<p>To create a fragment, you must create a subclass of {@link android.app.Fragment} (or an existing +subclass of it). The {@link android.app.Fragment} class has code that looks a lot like +an {@link android.app.Activity}. It contains callback methods similar to an activity, such +as {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()}, +{@link android.app.Fragment#onPause onPause()}, and {@link android.app.Fragment#onStop onStop()}. In +fact, if you're converting an existing Android application to use fragments, you might simply move +code from your activity's callback methods into the respective callback methods of your +fragment.</p> + +<p>Usually, you should implement at least the following lifecycle methods:</p> + +<dl> + <dt>{@link android.app.Fragment#onCreate onCreate()}</dt> + <dd>The system calls this when creating the fragment. Within your implementation, you should +initialize essential components of the fragment that you want to retain when the fragment is +paused or stopped, then resumed.</dd> + <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> + <dd>The system calls this when it's time for the fragment to draw its user interface for the +first time. To draw a UI for your fragment, you must return a {@link android.view.View} from this +method that is the root of your fragment's layout. You can return null if the fragment does not +provide a UI.</dd> + <dt>{@link android.app.Activity#onPause onPause()}</dt> + <dd>The system calls this method as the first indication that the user is leaving the +fragment (though it does not always mean the fragment is being destroyed). This is usually where you +should commit any changes that should be persisted beyond the current user session (because +the user might not come back).</dd> +</dl> + +<p>Most applications should implement at least these three methods for every fragment, but there are +several other callback methods you should also use to handle various stages of the +fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section +about <a href="#Lifecycle">Handling the Fragment Lifecycle</a>.</p> + + +<p>There are also a few subclasses that you might want to extend, instead of the base {@link +android.app.Fragment} class:</p> + +<dl> + <dt>{@link android.app.DialogFragment}</dt> + <dd>Displays a floating dialog. Using this class to create a dialog is a good alternative to using +the dialog helper methods in the {@link android.app.Activity} class, because you can +incorporate a fragment dialog into the back stack of fragments managed by the activity, +allowing the user to return to a dismissed fragment.</dd> + + <dt>{@link android.app.ListFragment}</dt> + <dd>Displays a list of items that are managed by an adapter (such as a {@link +android.widget.SimpleCursorAdapter}), similar to {@link android.app.ListActivity}. It provides +several methods for managing a list view, such as the {@link +android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} callback to +handle click events.</dd> + + <dt>{@link android.preference.PreferenceFragment}</dt> + <dd>Displays a hierarchy of {@link android.preference.Preference} objects as a list, similar to +{@link android.preference.PreferenceActivity}. This is useful when creating a "settings" +activity for your application.</dd> +</dl> + + +<h3 id="UI">Adding a user interface</h3> + +<p>A fragment is usually used as part of an activity's user interface and contributes its own +layout to the activity.</p> + +<p>To provide a layout for a fragment, you must implement the {@link +android.app.Fragment#onCreateView onCreateView()} callback method, which the Android system calls +when it's time for the fragment to draw its layout. Your implementation of this method must return a +{@link android.view.View} that is the root of your fragment's layout.</p> + +<p class="note"><strong>Note:</strong> If your fragment is a subclass of {@link +android.app.ListFragment}, the default implementation returns a {@link android.widget.ListView} from +{@link android.app.Fragment#onCreateView onCreateView()}, so you don't need to implement it.</p> + +<p>To return a layout from {@link +android.app.Fragment#onCreateView onCreateView()}, you can inflate it from a <a +href="{@docRoot}guide/topics/resources/layout-resource.html">layout resource</a> defined in XML. To +help you do so, {@link android.app.Fragment#onCreateView onCreateView()} provides a +{@link android.view.LayoutInflater} object.</p> + +<p>For example, here's a subclass of {@link android.app.Fragment} that loads a layout from the +{@code example_fragment.xml} file:</p> + +<pre> +public static class ExampleFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.example_fragment, container, false); + } +} +</pre> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>Creating a layout</h3> + <p>In the sample above, {@code R.layout.example_fragment} is a reference to a layout resource +named {@code example_fragment.xml} saved in the application resources. For information about how to +create a layout in XML, see the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> +documentation.</p> +</div> +</div> + +<p>The {@code container} parameter passed to {@link android.app.Fragment#onCreateView +onCreateView()} is the parent {@link android.view.ViewGroup} (from the activity's layout) in which +your fragment layout +will be inserted. The {@code savedInstanceState} parameter is a {@link android.os.Bundle} that +provides data about the previous instance of the fragment, if the fragment is being resumed +(restoring state is discussed more in the section about <a href="#Lifecycle">Handling the +Fragment Lifecycle</a>).</p> + +<p>The {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} method takes +three arguments:</p> +<ul> + <li>The resource ID of the layout you want to inflate.</li> + <li>The {@link android.view.ViewGroup} to be the parent of the inflated layout. Passing the {@code +container} is important in order for the system to apply layout parameters to the root view of the +inflated layout, specified by the parent view in which it's going.</li> + <li>A boolean indicating whether the inflated layout should be attached to the {@link +android.view.ViewGroup} (the second parameter) during inflation. (In this case, this +is false because the system is already inserting the inflated layout into the {@code +container}—passing true would create a redundant view group in the final layout.)</li> +</ul> + +<p>Now you've seen how to create a fragment that provides a layout. Next, you need to add +the fragment to your activity.</p> + + + +<h3 id="Adding">Adding a fragment to an activity</h3> + +<p>Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part +of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity +layout:</p> + +<ul> + <li><b>Declare the fragment inside the activity's layout file.</b> +<p>In this case, you can +specify layout properties for the fragment as if it were a view. For example, here's the layout +file for an activity with two fragments:</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <fragment android:name="com.example.news.ArticleListFragment" + android:id="@+id/list" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="match_parent" /> + <fragment android:name="com.example.news.ArticleReaderFragment" + android:id="@+id/viewer" + android:layout_weight="2" + android:layout_width="0dp" + android:layout_height="match_parent" /> +</LinearLayout> +</pre> + <p>The {@code android:name} attribute in the {@code <fragment>} specifies the {@link +android.app.Fragment} class to instantiate in the layout.</p> + +<p>When the system creates this activity layout, it instantiates each fragment specified in the +layout and calls the {@link android.app.Fragment#onCreateView onCreateView()} method for each one, +to retrieve each fragment's layout. The system inserts the {@link android.view.View} returned by the +fragment directly in place of the {@code <fragment>} element.</p> + +<div class="note"> + <p><strong>Note:</strong> Each fragment requires a unique identifier that +the system can use to restore the fragment if the activity is restarted (and which you can use to +capture the fragment to perform transactions, such as remove it). There are three ways to provide an +ID for a fragment:</p> + <ul> + <li>Supply the {@code android:id} attribute with a unique ID.</li> + <li>Supply the {@code android:tag} attribute with a unique string.</li> + <li>If you provide neither of the previous two, the system uses the ID of the container +view.</li> + </ul> +</div> + </li> + + <li><b>Or, programmatically add the fragment to an existing {@link android.view.ViewGroup}.</b> +<p>At any time while your activity is running, you can add fragments to your activity layout. You +simply need to specify a {@link +android.view.ViewGroup} in which to place the fragment.</p> + <p>To make fragment transactions in your activity (such as add, remove, or replace a +fragment), you must use APIs from {@link android.app.FragmentTransaction}. You can get an instance +of {@link android.app.FragmentTransaction} from your {@link android.app.Activity} like this:</p> + +<pre> +FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()} +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +</pre> + +<p>You can then add a fragment using the {@link +android.app.FragmentTransaction#add(int,Fragment) add()} method, specifying the fragment to add and +the view in which to insert it. For example:</p> + +<pre> +ExampleFragment fragment = new ExampleFragment(); +fragmentTransaction.add(R.id.fragment_container, fragment); +fragmentTransaction.commit(); +</pre> + + <p>The first argument passed to {@link android.app.FragmentTransaction#add(int,Fragment) add()} +is the {@link android.view.ViewGroup} in which the fragment should be placed, specified by +resource ID, and the second parameter is the fragment to add.</p> + <p>Once you've made your changes with +{@link android.app.FragmentTransaction}, you must +call {@link android.app.FragmentTransaction#commit} for the changes to take effect.</p> + </li> +</ul> + + +<h4 id="AddingWithoutUI">Adding a fragment without a UI</h4> + +<p>The examples above show how to add a fragment to your activity in order to provide a UI. However, +you can also use a fragment to provide a background behavior for the activity without presenting +additional UI.</p> + +<p>To add a fragment without a UI, add the fragment from the activity using {@link +android.app.FragmentTransaction#add(Fragment,String)} (supplying a unique string "tag" for the +fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a +view in the activity layout, it does not receive a call to {@link +android.app.Fragment#onCreateView onCreateView()}. So you don't need to implement that method.</p> + +<p>Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also +supply string tags to fragments that do have a UI—but if the fragment does not have a +UI, then the string tag is the only way to identify it. If you want to get the fragment from the +activity later, you need to use {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()}.</p> + +<p>For an example activity that uses a fragment as a background worker, without a UI, see the <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.html">{@code +FragmentRetainInstance.java}</a> sample.</p> + + + +<h2 id="Managing">Managing Fragments</h2> + +<p>To manage the fragments in your activity, you need to use {@link android.app.FragmentManager}. To +get it, call {@link android.app.Activity#getFragmentManager()} from your activity.</p> + +<p>Some things that you can do with {@link android.app.FragmentManager} include:</p> + +<ul> + <li>Get fragments that exist in the activity, with {@link +android.app.FragmentManager#findFragmentById findFragmentById()} (for fragments that provide a UI in +the activity layout) or {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()} (for fragments that do or don't provide a UI).</li> + <li>Pop fragments off the back stack, with {@link +android.app.FragmentManager#popBackStack()} (simulating a BACK command by the user).</li> + <li>Register a listener for changes to the back stack, with {@link +android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li> +</ul> + +<p>For more information about these methods and others, refer to the {@link +android.app.FragmentManager} class documentation.</p> + +<p>As demonstrated in the previous section, you can also use {@link android.app.FragmentManager} +to open a {@link android.app.FragmentTransaction}, which allows you to perform transactions, such as +add and remove fragments.</p> + + +<h2 id="Transactions">Performing Fragment Transactions</h2> + +<p>A great feature about using fragments in your activity is the ability to add, remove, replace, +and perform other actions with them, in response to user interaction. Each set of changes that you +commit to the activity is called a transaction and you can perform one using APIs in {@link +android.app.FragmentTransaction}. You can also save each transaction to a back stack managed by the +activity, allowing the user to navigate backward through the fragment changes (similar to navigating +backward through activities).</p> + +<p>You can acquire an instance of {@link android.app.FragmentTransaction} from the {@link +android.app.FragmentManager} like this:</p> + +<pre> +FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}; +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +</pre> + +<p>Each transaction is a set of changes that you want to perform at the same time. You can set +up all the changes you want to perform for a given transaction using methods such as {@link +android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()}, +and {@link android.app.FragmentTransaction#replace replace()}. Then, to apply the transaction +to the activity, you must call {@link android.app.FragmentTransaction#commit()}.</p> +</dl> + +<p>Before you call {@link +android.app.FragmentTransaction#commit()}, however, you might want to call {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, in order to add the transaction +to a back stack of fragment transactions. This back stack is managed by the activity and allows +the user to return to the previous fragment state, by pressing the BACK key.</p> + +<p>For example, here's how you can replace one fragment with another, and preserve the previous +state in the back stack:</p> + +<pre> +// Create new fragment and transaction +Fragment newFragment = new ExampleFragment(); +FragmentTransaction transaction = getFragmentManager().beginTransaction(); + +// Replace whatever is in the fragment_container view with this fragment, +// and add the transaction to the back stack +transaction.replace(R.id.fragment_container, newFragment); +transaction.addToBackStack(null); + +// Commit the transaction +transaction.commit(); +</pre> + +<p>In this example, {@code newFragment} replaces whatever fragment (if any) is currently in the +layout container identified by the {@code R.id.fragment_container} ID. By calling {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, the replace transaction is +saved to the back stack so the user can reverse the transaction and bring back the +previous fragment by pressing the BACK key.</p> + +<p>If you add multiple changes to the transaction (such as another {@link +android.app.FragmentTransaction#add add()} or {@link android.app.FragmentTransaction#remove +remove()}) and call {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, then all changes applied +before you call {@link android.app.FragmentTransaction#commit commit()} are added to the +back stack as a single transaction and the BACK key will reverse them all together.</p> + +<p>The order in which you add changes to a {@link android.app.FragmentTransaction} doesn't matter, +except:</p> +<ul> + <li>You must call {@link android.app.FragmentTransaction#commit()} last</li> + <li>If you're adding multiple fragments to the same container, then the order in which +you add them determines the order they appear in the view hierarchy</li> +</ul> + +<p>If you do not call {@link android.app.FragmentTransaction#addToBackStack(String) +addToBackStack()} when you perform a transaction that removes a fragment, then that fragment is +destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you +do call {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} when +removing a fragment, then the fragment is <em>stopped</em> and will be resumed if the user navigates +back.</p> + +<p class="note"><strong>Tip:</strong> For each fragment transaction, you can apply a transition +animation, by calling {@link android.app.FragmentTransaction#setTransition setTransition()} before +you commit.</p> + +<p>Calling {@link android.app.FragmentTransaction#commit()} does not perform the transaction +immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon +as the thread is able to do so. If necessary, however, you may call {@link +android.app.FragmentManager#executePendingTransactions()} from your UI thread to immediately execute +transactions submitted by {@link android.app.FragmentTransaction#commit()}. Doing so is +usually not necessary unless the transaction is a dependency for jobs in other threads.</p> + +<p class="caution"><strong>Caution:</strong> You can commit a transaction using {@link +android.app.FragmentTransaction#commit commit()} only prior to the activity <a +href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">saving its +state</a> (when the user leaves the activity). If you attempt to commit after that point, an +exception will be thrown. This is because the state after the commit can be lost if the activity +needs to be restored. For situations in which its okay that you lose the commit, use {@link +android.app.FragmentTransaction#commitAllowingStateLoss()}.</p> + + + + +<h2 id="CommunicatingWithActivity">Communicating with the Activity</h2> + +<p>Although a {@link android.app.Fragment} is implemented as an object that's independent from an +{@link android.app.Activity} and can be used inside multiple activities, a given instance of +a fragment is directly tied to the activity that contains it.</p> + +<p>Specifically, the fragment can access the {@link android.app.Activity} instance with {@link +android.app.Fragment#getActivity()} and easily perform tasks such as find a view in the +activity layout:</p> + +<pre> +View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list); +</pre> + +<p>Likewise, your activity can call methods in the fragment by acquiring a reference to the +{@link android.app.Fragment} from {@link android.app.FragmentManager}, using {@link +android.app.FragmentManager#findFragmentById findFragmentById()} or {@link +android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. For example:</p> + +<pre> +ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment); +</pre> + + +<h4 id="EventCallbacks">Creating event callbacks to the activity</h4> + +<p>In some cases, you might need a fragment to share events with the activity. A good way to do that +is to define a callback interface inside the fragment and require that the host activity implement +it. When the activity receives a callback through the interface, it can share the information with +other fragments in the layout as necessary.</p> + +<p>For example, if a news application has two fragments in an activity—one to show a list of +articles (fragment A) and another to display an article (fragment B)—then fragment A must tell +the activity when a list item is selected so that it can tell fragment B to display the article. In +this case, the {@code OnArticleSelectedListener} interface is declared inside fragment A:</p> + +<pre> +public static class FragmentA extends ListFragment { + ... + // Container Activity must implement this interface + public interface OnArticleSelectedListener { + public void onArticleSelected(Uri articleUri); + } + ... +} +</pre> + +<p>Then the activity that hosts the fragment implements the {@code OnArticleSelectedListener} +interface and +overrides {@code onArticleSelected()} to notify fragment B of the event from fragment A. To ensure +that the host activity implements this interface, fragment A's {@link +android.app.Fragment#onAttach onAttach()} callback method (which the system calls when adding +the fragment to the activity) instantiates an instance of {@code OnArticleSelectedListener} by +casting the {@link android.app.Activity} that is passed into {@link android.app.Fragment#onAttach +onAttach()}:</p> + +<pre> +public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnArticleSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); + } + } + ... +} +</pre> + +<p>If the activity has not implemented the interface, then the fragment throws a +{@link java.lang.ClassCastException}. +On success, the {@code mListener} member holds a reference to activity's implementation of +{@code OnArticleSelectedListener}, so that fragment A can share events with the activity by calling +methods defined by the {@code OnArticleSelectedListener} interface. For example, if fragment A is an +extension of {@link android.app.ListFragment}, each time +the user clicks a list item, the system calls {@link android.app.ListFragment#onListItemClick +onListItemClick()} in the fragment, which then calls {@code onArticleSelected()} to share +the event with the activity:</p> + +<pre> +public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + // Append the clicked item's row ID with the content provider Uri + Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id); + // Send the event and Uri to the host activity + mListener.onArticleSelected(noteUri); + } + ... +} +</pre> + +<p>The {@code id} parameter passed to {@link +android.app.ListFragment#onListItemClick onListItemClick()} is the row ID of the clicked item, +which the activity (or other fragment) uses to fetch the article from the application's {@link +android.content.ContentProvider}.</p> + +<p><!--To see a complete implementation of this kind of callback interface, see the <a +href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->More information about +using a content provider is available in the <a +href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> document.</p> + + + +<h3 id="ActionBar">Adding items to the Action Bar</h3> + +<p>Your fragments can contribute menu items to the activity's <a +href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> (and, consequently, the <a +href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>) by implementing +{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. In order +for this method to receive calls, however, you must call {@link +android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} during {@link +android.app.Fragment#onCreate(Bundle) onCreate()}, to indicate that the fragment +would like to add items to the Options Menu (otherwise, the fragment will not receive a call to +{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p> + +<p>Any items that you then add to the Options Menu from the fragment are appended to the existing +menu items. The fragment also receives callbacks to {@link +android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} when a menu item +is selected.</p> + +<p>You can also register a view in your fragment layout to provide a context menu by calling {@link +android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. When the user opens +the context menu, the fragment receives a call to {@link +android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) +onCreateContextMenu()}. When the user selects an item, the fragment receives a call to {@link +android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p> + +<p class="note"><strong>Note:</strong> Although your fragment receives an on-item-selected callback +for each menu item it adds, the activity is first to receive the respective callback when the user +selects a menu item. If the activity's implementation of the on-item-selected callback does not +handle the selected item, then the event is passed to the fragment's callback. This is true for +the Options Menu and context menus.</p> + +<p>For more information about menus, see <a href="{@docRoot}guide/topics/ui/menus.html">Creating +Menus</a> and <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>.</p> + + + + +<h2 id="Lifecycle">Handling the Fragment Lifecycle</h2> + +<div class="figure" style="width:403px"> +<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt=""/> +<p class="img-caption"><strong>Figure 3.</strong> The activity lifecycle's affect on the fragment +lifecycle.</p> +</div> + +<p>Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like +an activity, a fragment can exist in three states:</p> + +<dl> + <dt><i>Resumed</i></dt> + <dd>The fragment is visible in the running activity.</dd> + + <dt><i>Paused</i></dt> + <dd>Another activity is in the foreground and has focus, but the activity in which this +fragment lives is still visible (the foreground activity is partially transparent or doesn't +cover the entire screen).</dd> + + <dt><i>Stopped</i></dt> + <dd>The fragment is not visible. Either the host activity has been stopped or the +fragment has been removed from the activity but added to the back stack. A stopped fragment is +still alive (all state and member information is retained by the system). However, it is no longer +visible to the user and will be killed if the activity is killed.</dd> +</dl> + +<p>Also like an activity, you can retain the state of a fragment using a {@link +android.os.Bundle}, in case the activity's process is killed and you need to restore the +fragment state when the activity is recreated. You can save the state during the fragment's {@link +android.app.Fragment#onSaveInstanceState onSaveInstanceState()} callback and restore it during +either {@link android.app.Fragment#onCreate onCreate()}, {@link +android.app.Fragment#onCreateView onCreateView()}, or {@link +android.app.Fragment#onActivityCreated onActivityCreated()}. For more information about saving +state, see the <a +href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">Activities</a> +document.</p> + +<p>The most significant difference in lifecycle between an activity and a fragment is how one is +stored in its respective back stack. An activity is placed into a back stack of activities +that's managed by the system when it's stopped, by default (so that the user can navigate back +to it with the BACK key, as discussed in <a +href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>). +However, a fragment is placed into a back stack managed by the host activity only when you +explicitly request that the instance be saved by calling {@link +android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} during a transaction that +removes the fragment.</p> + +<p>Otherwise, managing the fragment lifecycle is very similar to managing the activity +lifecycle. So, the same practices for <a +href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">managing the activity +lifecycle</a> also apply to fragments. What you also need to understand, though, is how the life +of the activity affects the life of the fragment.</p> + + +<h3 id="CoordinatingWithActivity">Coordinating with the activity lifecycle</h3> + +<p>The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the +fragment, such that each lifecycle callback for the activity results in a similar callback for each +fragment. For example, when the activity receives {@link android.app.Activity#onPause}, each +fragment in the activity receives {@link android.app.Fragment#onPause}.</p> + +<p>Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the +activity in order to perform actions such as build and destroy the fragment's UI. These additional +callback methods are:</p> + +<dl> + <dt>{@link android.app.Fragment#onAttach onAttach()}</dt> + <dd>Called when the fragment has been associated with the activity (the {@link +android.app.Activity} is passed in here).</dd> + <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> + <dd>Called to create the view hierarchy associated with the fragment.</dd> + <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt> + <dd>Called when the activity's {@link android.app.Activity#onCreate +onCreate()} method has returned.</dd> + <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt> + <dd>Called when the view hierarchy associated with the fragment is being removed.</dd> + <dt>{@link android.app.Fragment#onDetach onDetach()}</dt> + <dd>Called when the fragment is being disassociated from the activity.</dd> +</dl> + +<p>The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated +by figure 3. In this figure, you can see how each successive state of the activity determines which +callback methods a fragment may receive. For example, when the activity has received its {@link +android.app.Activity#onCreate onCreate()} callback, a fragment in the activity receives no more than +the {@link android.app.Fragment#onActivityCreated onActivityCreated()} callback.</p> + +<p>Once the activity reaches the resumed state, you can freely add and remove fragments to the +activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment +change independently.</p> + +<p>However, when the activity leaves the resumed state, the fragment again is pushed through its +lifecycle by the activity.</p> + + + + +<h2 id="Example">Example</h2> + +<p>To bring everything discussed in this document together, here's an example of an activity +using two fragments to create a two-pane layout. The activity below includes one fragment to +show a list of Shakespeare play titles and another to show a summary of the play when selected +from the list. It also demonstrates how to provide different configurations of the fragments, +based on the screen configuration.</p> + +<p class="note"><strong>Note:</strong> The complete source code for this activity is available in +<a href="resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code +FragmentLayout.java}</a>.</p> + +<p>The main activity applies a layout in the usual way, during {@link +android.app.Activity#onCreate onCreate()}:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main} + +<p>The layout applied is {@code fragment_layout.xml}:</p> + +{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout} + +<p>Using this layout, the system instantiates the {@code TitlesFragment} (which lists the play +titles) as soon as the activity loads the layout, while the {@link android.widget.FrameLayout} +(where the fragment for showing the play summary will go) consumes space on the right side of the +screen, but remains empty at first. As you'll see below, it's not until the user selects an item +from the list that a fragment is placed into the {@link android.widget.FrameLayout}.</p> + +<p>However, not all screen configurations are wide enough to show both the list of +plays and the summary, side by side. So, the layout above is used only for the landscape +screen configuration, by saving it at {@code res/layout-land/fragment_layout.xml}.</p> + +<p>Thus, when the screen is in portrait orientation, the system applies the following layout, which +is saved at {@code res/layout/fragment_layout.xml}:</p> + +{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} + +<p>This layout includes only {@code TitlesFragment}. This means that, when the device is in +portrait orientation, only the list of play titles is visible. So, when the user clicks a list +item in this configuration, the application will start a new activity to show the summary, +instead of loading a second fragment.</p> + +<p>Next, you can see how this is accomplished in the fragment classes. First is {@code +TitlesFragment}, which shows the list of Shakespeare play titles. This fragment extends {@link +android.app.ListFragment} and relies on it to handle most of the list view work.</p> + +<p>As you inspect this code, notice that there are two possible behaviors when the user clicks a +list item: depending on which of the two layouts is active, it can either create and display a new +fragment to show the details in the same activity (adding the fragment to the {@link +android.widget.FrameLayout}), or start a new activity (where the fragment can be shown).</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles} + +<p>The second fragment, {@code DetailsFragment} shows the play summary for the item selected from +the list from {@code TitlesFragment}:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details} + +<p>Recall from the {@code TitlesFragment} class, that, if the user clicks a list item and the +current layout does <em>not</em> include the {@code R.id.details} view (which is where the +{@code DetailsFragment} belongs), then the application starts the {@code DetailsActivity} +activity to display the content of the item.</p> + +<p>Here is the {@code DetailsActivity}, which simply embeds the {@code DetailsFragment} to display +the selected play summary when the screen is in portrait orientation:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java +details_activity} + +<p>Notice that this activity finishes itself if the configuration is landscape, so that the main +activity can take over and display the {@code DetailsFragment} alongside the {@code TitlesFragment}. +This can happen if the user begins the {@code DetailsActivity} while in portrait orientation, but +then rotates to landscape (which restarts the current activity).</p> + + +<p>For more samples using fragments (and complete source files for this example), +see the sample code available in <a +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment"> +ApiDemos</a> (available for download from the <a +href="{@docRoot}resources/samples/get.html">Samples SDK component</a>).</p> + + diff --git a/docs/html/guide/topics/fundamentals/services.jd b/docs/html/guide/topics/fundamentals/services.jd new file mode 100644 index 0000000..df1eace --- /dev/null +++ b/docs/html/guide/topics/fundamentals/services.jd @@ -0,0 +1,860 @@ +page.title=Services +parent.title=Application Fundamentals +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<ol id="qv"> +<h2>Quickview</h2> +<ul> + <li>A service can run in the background to perform work even while the user is in a different +application</li> + <li>A service can allow other components to bind to it, in order to interact with it and +perform interprocess communication</li> + <li>A service runs in the main thread of the application that hosts it, by default</li> +</ul> +<h2>In this document</h2> +<ol> +<li><a href="#Basics">The Basics</a></li> +<ol> + <li><a href="#Declaring">Declaring a service in the manifest</a></li> +</ol> +<li><a href="#CreatingAService">Creating a Started Service</a> + <ol> + <li><a href="#ExtendingIntentService">Extending the IntentService class</a></li> + <li><a href="#ExtendingService">Extending the Service class</a></li> + <li><a href="#StartingAService">Starting a service</a></li> + <li><a href="#Stopping">Stopping a service</a></li> + </ol> +</li> +<li><a href="#CreatingBoundService">Creating a Bound Service</a></li> +<li><a href="#Notifications">Sending Notifications to the User</a></li> +<li><a href="#Foreground">Running a Service in the Foreground</a></li> +<li><a href="#Lifecycle">Managing the Lifecycle of a Service</a> +<ol> + <li><a href="#LifecycleCallbacks">Implementing the lifecycle callbacks</a></li> +</ol> +</li> +</ol> + +<h2>Key classes</h2> +<ol> + <li>{@link android.app.Service}</li> + <li>{@link android.app.IntentService}</li> +</ol> + +<h2>Samples</h2> +<ol> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code + ServiceStartArguments}</a></li> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code + LocalService}</a></li> +</ol> + +<h2>See also</h2> +<ol> +<li><a href="{@docRoot}guide/topics/fundamentals/bound-services.html">Bound Services</a></li> +</ol> + +</div> + + +<p>A {@link android.app.Service} is an application component that can perform +long-running operations in the background and does not provide a user interface. Another +application component can start a service and it will continue to run in the background even if the +user switches to another application. Additionally, a component can bind to a service to +interact with it and even perform interprocess communication (IPC). For example, a service might +handle network transactions, play music, perform file I/O, or interact with a content provider, all +from the background.</p> + +<p>A service can essentially take two forms:</p> + +<dl> + <dt>Started</dt> + <dd>A service is "started" when an application component (such as an activity) starts it by +calling {@link android.content.Context#startService startService()}. Once started, a service +can run in the background indefinitely, even if the component that started it is destroyed. Usually, +a started service performs a single operation and does not return a result to the caller. +For example, it might download or upload a file over the network. When the operation is done, the +service should stop itself.</dd> + <dt>Bound</dt> + <dd>A service is "bound" when an application component binds to it by calling {@link +android.content.Context#bindService bindService()}. A bound service offers a client-server +interface that allows components to interact with the service, send requests, get results, and even +do so across processes with interprocess communication (IPC). A bound service runs only as long as +another application component is bound to it. Multiple components can bind to the service at once, +but when all of them unbind, the service is destroyed.</dd> +</dl> + +<p>Although this documentation generally discusses these two types of services separately, your +service can work both ways—it can be started (to run indefinitely) and also allow binding. +It's simply a matter of whether you implement a couple callback methods: {@link +android.app.Service#onStartCommand onStartCommand()} to allow components to start it and {@link +android.app.Service#onBind onBind()} to allow binding.</p> + +<p>Regardless of whether your application is started, bound, or both, any application component +can use the service (even from a separate application), in the same way that any component can use +an activity—by starting it with an {@link android.content.Intent}. However, you can declare +the service as private, in the manifest file, and block access from other applications. This is +discussed more in the section about <a href="#Declaring">Declaring the service in the +manifest</a>.</p> + +<p class="caution"><strong>Caution:</strong> A service runs in the +main thread of its hosting process—the service does <strong>not</strong> create its own thread +and does <strong>not</strong> run in a separate process (unless you specify otherwise). This means +that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 +playback or networking), you should create a new thread within the service to do that work. By using +a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the +application's main thread can remain dedicated to user interaction with your activities.</p> + + +<h2 id="Basics">The Basics</h2> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>Should you use a service or a thread?</h3> + <p>A service is simply a component that can run in the background even when the user is not +interacting with your application. Thus, you should create a service only if that is what you +need.</p> + <p>If you need to perform work outside your main thread, but only while the user is interacting +with your application, then you should probably instead create a new thread and not a service. For +example, if you want to play some music, but only while your activity is running, you might create +a thread in {@link android.app.Activity#onCreate onCreate()}, start running it in {@link +android.app.Activity#onStart onStart()}, then stop it in {@link android.app.Activity#onStop +onStop()}. Also consider using {@link android.os.AsyncTask} or {@link android.os.HandlerThread}, +instead of the traditional {@link java.lang.Thread} class. See the <a +href="{@docRoot}guide/topics/fundamentals/processes-and-threading.html#Threads">Processes and +Threading</a> document for more information about threads.</p> + <p>Remember that if you do use a service, it still runs in your application's main thread by +default, so you should still create a new thread within the service if it performs intensive or +blocking operations.</p> +</div> +</div> + +<p>To create a service, you must create a subclass of {@link android.app.Service} (or one +of its existing subclasses). In your implementation, you need to override some callback methods that +handle key aspects of the service lifecycle and provide a mechanism for components to bind to +the service, if appropriate. The most important callback methods you should override are:</p> + +<dl> + <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt> + <dd>The system calls this method when another component, such as an activity, +requests that the service be started, by calling {@link android.content.Context#startService +startService()}. Once this method executes, the service is started and can run in the +background indefinitely. If you implement this, it is your responsibility to stop the service when +its work is done, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link +android.content.Context#stopService stopService()}. (If you only want to provide binding, you don't +need to implement this method.)</dd> + <dt>{@link android.app.Service#onBind onBind()}</dt> + <dd>The system calls this method when another component wants to bind with the +service (such as to perform RPC), by calling {@link android.content.Context#bindService +bindService()}. In your implementation of this method, you must provide an interface that clients +use to communicate with the service, by returning an {@link android.os.IBinder}. You must always +implement this method, but if you don't want to allow binding, then you should return null.</dd> + <dt>{@link android.app.Service#onCreate()}</dt> + <dd>The system calls this method when the service is first created, to perform one-time setup +procedures (before it calls either {@link android.app.Service#onStartCommand onStartCommand()} or +{@link android.app.Service#onBind onBind()}). If the service is already running, this method is not +called.</dd> + <dt>{@link android.app.Service#onDestroy()}</dt> + <dd>The system calls this method when the service is no longer used and is being destroyed. +Your service should implement this to clean up any resources such as threads, registered +listeners, receivers, etc. This is the last call the service receives.</dd> +</dl> + +<p>If a component starts the service by calling {@link +android.content.Context#startService startService()} (which results in a call to {@link +android.app.Service#onStartCommand onStartCommand()}), then the service +remains running until it stops itself with {@link android.app.Service#stopSelf()} or another +component stops it by calling {@link android.content.Context#stopService stopService()}.</p> + +<p>If a component calls +{@link android.content.Context#bindService bindService()} to create the service (and {@link +android.app.Service#onStartCommand onStartCommand()} is <em>not</em> called), then the service runs +only as long as the component is bound to it. Once the service is unbound from all clients, the +system destroys it.</p> + +<p>The Android system will force-stop a service only when memory is low and it must recover system +resources for the activity that has user focus. If the service is bound to an activity that has user +focus, then it's less likely to be killed, and if the service is declared to <a +href="#Foreground">run in the foreground</a> (discussed later), then it will almost never be killed. +Otherwise, if the service was started and is long-running, then the system will lower its position +in the list of background tasks over time and the service will become highly susceptible to +killing—if your service is started, then you must design it to gracefully handle restarts +by the system. If the system kills your service, it restarts it as soon as resources become +available again (though this also depends on the value you return from {@link +android.app.Service#onStartCommand onStartCommand()}, as discussed later). For more information +about when the system might destroy a service, see the <a +href="{@docRoot}guide/topics/fundamentals/processes-and-threading.html">Processes and Threading</a> +document.</p> + +<p>In the following sections, you'll see how you can create each type of service and how to use +it from other application components.</p> + + + +<h3 id="Declaring">Declaring a service in the manifest</h3> + +<p>Like activities (and other components), you must declare all services in your application's +manifest file.</p> + +<p>To decalare your service, add a <a +href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element +as a child of the <a +href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> +element. For example:</p> + +<pre> +<manifest ... > + ... + <application ... > + <service android:name=".ExampleService" /> + ... + </application> +</manifest> +</pre> + +<p>There are other attributes you can include in the <a +href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element to +define properties such as permissions required to start the service and the process in +which the service should run. See the <a +href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element +reference for more information.</p> + +<p>Just like an activity, a service can define intent filters that allow other components to +invoke the service using implicit intents. By declaring intent filters, components +from any application installed on the user's device can potentially start your service if your +service declares an intent filter that matches the intent another application passes to {@link +android.content.Context#startService startService()}.</p> + +<p>If you plan on using your service only locally (other applications do not use it), then you +don't need to (and should not) supply any intent filters. Without any intent filters, you must +start the service using an intent that explicitly names the service class. More information +about <a href="#StartingAService">starting a service</a> is discussed below.</p> + +<p>Additionally, you can ensure that your service is private to your application only if +you include the <a +href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a> +attribute and set it to {@code "false"}. This is effective even if your service supplies intent +filters.</p> + +<p>For more information about creating intent filters for your service, see the <a +href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a> +document.</p> + + + +<h2 id="CreatingStartedService">Creating a Started Service</h2> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h2>Targeting Android 1.6 or lower</h2> + <p>If you're building an application for Android 1.6 or lower, you need +to implement {@link android.app.Service#onStart onStart()}, instead of {@link +android.app.Service#onStartCommand onStartCommand()} (in Android 2.0, +{@link android.app.Service#onStart onStart()} was deprecated in favor of {@link +android.app.Service#onStartCommand onStartCommand()}).</p> + <p>For more information about providing compatibility with versions of Android older than 2.0, see +the {@link android.app.Service#onStartCommand onStartCommand()} documentation.</p> +</div> +</div> + +<p>A started service is one that another component starts by calling {@link +android.content.Context#startService startService()}, resulting in a call to the service's +{@link android.app.Service#onStartCommand onStartCommand()} method.</p> + +<p>When a service is started, it has a lifecycle that's independent of the +component that started it and the service can run in the background indefinitely, even if +the component that started it is destroyed. As such, the service should stop itself when its job +is done by calling {@link android.app.Service#stopSelf stopSelf()}, or another component can stop it +by calling {@link android.content.Context#stopService stopService()}.</p> + +<p>An application component such as an activity can start the service by calling {@link +android.content.Context#startService startService()} and passing an {@link android.content.Intent} +that specifies the service and includes any data for the service to use. The service receives +this {@link android.content.Intent} in the {@link android.app.Service#onStartCommand +onStartCommand()} method.</p> + +<p>For instance, suppose an activity needs to save some data to an online database. The activity can +start a companion service and deliver it the data to save by passing an intent to {@link +android.content.Context#startService startService()}. The service receives the intent in {@link +android.app.Service#onStartCommand onStartCommand()}, connects to the Internet and performs the +database transaction. When the transaction is done, the service stops itself and it is +destroyed.</p> + +<p class="caution"><strong>Caution:</strong> A services runs in the same process as the application +in which it is declared and in the main thread of that application, by default. So, if your service +performs intensive or blocking operations while the user interacts with an activity from the same +application, the service will slow down activity performance. To avoid impacting application +performance, you should start a new thread inside the service.</p> + +<p>Traditionally, there are two classes you can extend to create a started service:</p> +<dl> + <dt>{@link android.app.Service}</dt> + <dd>This is the base class for all services. When you extend this class, it's important that +you create a new thread in which to do all the service's work, because the service uses your +application's main thread, by default, which could slow the performance of any activity your +application is running.</dd> + <dt>{@link android.app.IntentService}</dt> + <dd>This is a subclass of {@link android.app.Service} that uses a worker thread to handle all +start requests, one at a time. This is the best option if you don't require that your service +handle multiple requests simultaneously. All you need to do is implement {@link +android.app.IntentService#onHandleIntent onHandleIntent()}, which receives the intent for each +start request so you can do the background work.</dd> +</dl> + +<p>The following sections describe how you can implement your service using either one for these +classes.</p> + + +<h3 id="ExtendingIntentService">Extending the IntentService class</h3> + +<p>Because most started services don't need to handle multiple requests simultaneously +(which can actually be a dangerous multi-threading scenario), it's probably best if you +implement your service using the {@link android.app.IntentService} class.</p> + +<p>The {@link android.app.IntentService} does the following:</p> + +<ul> + <li>Creates a default worker thread that executes all intents delivered to {@link +android.app.Service#onStartCommand onStartCommand()} separate from your application's main +thread.</li> + <li>Creates a work queue that passes one intent at a time to your {@link +android.app.IntentService#onHandleIntent onHandleIntent()} implementation, so you never have to +worry about multi-threading.</li> + <li>Stops the service after all start requests have been handled, so you never have to call +{@link android.app.Service#stopSelf}.</li> + <li>Provides default implementation of {@link android.app.IntentService#onBind onBind()} that +returns null.</li> + <li>Provides a default implementation of {@link android.app.IntentService#onStartCommand +onStartCommand()} that sends the intent to the work queue and then to your {@link +android.app.IntentService#onHandleIntent onHandleIntent()} implementation.</li> +</ul> + +<p>All this adds up to the fact that all you need to do is implement {@link +android.app.IntentService#onHandleIntent onHandleIntent()} to do the work provided by the +client. (Though, you also need to provide a small constructor for the service.)</p> + +<p>Here's an example implementation of {@link android.app.IntentService}:</p> + +<pre> +public class HelloIntentService extends IntentService { + + /** + * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} + * constructor with a name for the worker thread. + */ + public HelloIntentService() { + super("HelloIntentService"); + } + + /** + * The IntentService calls this method from the default worker thread with + * the intent that started the service. When this method returns, IntentService + * stops the service, as appropriate. + */ + @Override + protected void onHandleIntent(Intent intent) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + } +} +</pre> + +<p>That's all you need: a constructor and an implementation of {@link +android.app.IntentService#onHandleIntent onHandleIntent()}.</p> + +<p>If you decide to also override other callback methods, such as {@link +android.app.IntentService#onCreate onCreate()}, {@link +android.app.IntentService#onStartCommand onStartCommand()}, or {@link +android.app.IntentService#onDestroy onDestroy()}, be sure to call the super implementation, so +that the {@link android.app.IntentService} can properly handle the life of the worker thread.</p> + +<p>For example, {@link android.app.IntentService#onStartCommand onStartCommand()} must return +the default implementation (which is how the intent gets delivered to {@link +android.app.IntentService#onHandleIntent onHandleIntent()}):</p> + +<pre> +@Override +public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + return super.onStartCommand(intent,flags,startId); +} +</pre> + +<p>Besides {@link android.app.IntentService#onHandleIntent onHandleIntent()}, the only method +from which you don't need to call the super class is {@link android.app.IntentService#onBind +onBind()} (but you only need to implement that if your service allows binding).</p> + +<p>In the next section, you'll see how the same kind of service is implemented when extending +the base {@link android.app.Service} class, which is a lot more code, but which might be +appropriate if you need to handle simultaneous start requests.</p> + + +<h3 id="ExtendingService">Extending the Service class</h3> + +<p>As you saw in the previous section, using {@link android.app.IntentService} makes your +implementation of a started service very simple. If, however, you require your service to +perform multi-threading (instead of processing start requests through a work queue), then you +can extend the {@link android.app.Service} class to handle each intent.</p> + +<p>For comparison, the following example code is an implementation of the {@link +android.app.Service} class that performs the exact same work as the example above using {@link +android.app.IntentService}. That is, for each start request, it uses a worker thread to perform the +job and processes only one request at a time.</p> + +<pre> +public class HelloService extends Service { + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, restart + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + } +} +</pre> + +<p>As you can see, it's a lot more work than using {@link android.app.IntentService}.</p> + +<p>However, because you handle each call to {@link android.app.Service#onStartCommand +onStartCommand()} yourself, you can perform multiple requests simultaneously. That's not what +this example does, but if that's what you want, then you can create a new thread for each +request and run them right away (instead of waiting for the previous request to finish).</p> + +<p>Notice that the {@link android.app.Service#onStartCommand onStartCommand()} method must return an +integer. The integer is a value that describes how the system should continue the service in the +event that the system kills it (as discussed above, the default implementation for {@link +android.app.IntentService} handles this for you, though you are able to modify it). The return value +from {@link android.app.Service#onStartCommand onStartCommand()} must be one of the following +constants:</p> + +<dl> + <dt>{@link android.app.Service#START_NOT_STICKY}</dt> + <dd>If the system kills the service after {@link android.app.Service#onStartCommand +onStartCommand()} returns, <em>do not</em> recreate the service, unless there are pending +intents to deliver. This is the safest option to avoid running your service when not necessary +and when your application can simply restart any unfinished jobs.</dd> + <dt>{@link android.app.Service#START_STICKY}</dt> + <dd>If the system kills the service after {@link android.app.Service#onStartCommand +onStartCommand()} returns, recreate the service and call {@link +android.app.Service#onStartCommand onStartCommand()}, but <em>do not</em> redeliver the last intent. +Instead, the system calls {@link android.app.Service#onStartCommand onStartCommand()} with a +null intent, unless there were pending intents to start the service, in which case, +those intents are delivered. This is suitable for media players (or similar services) that are not +executing commands, but running indefinitely and waiting for a job.</dd> + <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt> + <dd>If the system kills the service after {@link android.app.Service#onStartCommand +onStartCommand()} returns, recreate the service and call {@link +android.app.Service#onStartCommand onStartCommand()} with the last intent that was delivered to the +service. Any pending intents are delivered in turn. This is suitable for services that are +actively performing a job that should be immediately resumed, such as downloading a file.</dd> +</dl> +<p>For more details about these return values, see the linked reference documentation for each +constant.</p> + + + +<h3 id="StartingAService">Starting a Service</h3> + +<p>You can start a service from an activity or other application component by passing an +{@link android.content.Intent} (specifying the service to start) to {@link +android.content.Context#startService startService()}. The Android system calls the service's {@link +android.app.Service#onStartCommand onStartCommand()} method and passes it the {@link +android.content.Intent}. (You should never call {@link android.app.Service#onStartCommand +onStartCommand()} directly.)</p> + +<p>For example, an activity can start the example service in the previous section ({@code +HelloSevice}) using an explicit intent with {@link android.content.Context#startService +startService()}:</p> + +<pre> +Intent intent = new Intent(this, HelloService.class); +startService(intent); +</pre> + +<p>The {@link android.content.Context#startService startService()} method returns immediately and +the Android system calls the service's {@link android.app.Service#onStartCommand +onStartCommand()} method. If the service is not already running, the system first calls {@link +android.app.Service#onCreate onCreate()}, then calls {@link android.app.Service#onStartCommand +onStartCommand()}.</p> + +<p>If the service does not also provide binding, the intent delivered with {@link +android.content.Context#startService startService()} is the only mode of communication between the +application component and the service. However, if you want the service to send a result back, then +the client that starts the service can create a {@link android.app.PendingIntent} for a broadcast +(with {@link android.app.PendingIntent#getBroadcast getBroadcast()}) and deliver it to the service +in the {@link android.content.Intent} that starts the service. The service can then use the +broadcast to deliver a result.</p> + +<p>Multiple requests to start the service result in multiple corresponding calls to the service's +{@link android.app.Service#onStartCommand onStartCommand()}. However, only one request to stop +the service (with {@link android.app.Service#stopSelf stopSelf()} or {@link +android.content.Context#stopService stopService()}) is required to stop it.</p> + + +<h3 id="Stopping">Stopping a service</h3> + +<p>A started service must manage its own lifecycle. That is, the system does not stop or +destroy the service unless it must recover system memory and the service +continues to run after {@link android.app.Service#onStartCommand onStartCommand()} returns. So, +the service must stop itself by calling {@link android.app.Service#stopSelf stopSelf()} or another +component can stop it by calling {@link android.content.Context#stopService stopService()}.</p> + +<p>Once requested to stop with {@link android.app.Service#stopSelf stopSelf()} or {@link +android.content.Context#stopService stopService()}, the system destroys the service as soon as +possible.</p> + +<p>However, if your service handles multiple requests to {@link +android.app.Service#onStartCommand onStartCommand()} concurrently, then you shouldn't stop the +service when you're done processing a start request, because you might have since received a new +start request (stopping at the end of the first request would terminate the second one). To avoid +this problem, you can use {@link android.app.Service#stopSelf(int)} to ensure that your request to +stop the service is always based on the most recent start request. That is, when you call {@link +android.app.Service#stopSelf(int)}, you pass the ID of the start request (the <code>startId</code> +delivered to {@link android.app.Service#onStartCommand onStartCommand()}) to which your stop request +corresponds. Then if the service received a new start request before you were able to call {@link +android.app.Service#stopSelf(int)}, then the ID will not match and the service will not stop.</p> + +<p class="caution"><strong>Caution:</strong> It's important that your application stops its services +when it's done working, to avoid wasting system resources and consuming battery power. If necessary, +other components can stop the service by calling {@link +android.content.Context#stopService stopService()}. Even if you enable binding for the service, +you must always stop the service yourself if it ever received a call to {@link +android.app.Service#onStartCommand onStartCommand()}.</p> + +<p>For more information about the lifecycle of a service, see the section below about <a +href="#Lifecycle">Managing the Lifecycle of a Service</a>.</p> + + + +<h2 id="CreatingBoundService">Creating a Bound Service</h2> + +<p>A bound service is one that allows application components to bind to it by calling {@link +android.content.Context#bindService bindService()} in order to create a long-standing connection +(and generally does not allow components to <em>start</em> it by calling {@link +android.content.Context#startService startService()}).</p> + +<p>You should create a bound service when you want to interact with the service from activities +and other components in your application or to expose some of your application's functionality to +other applications, through interprocess communication (IPC).</p> + +<p>To create a bound service, you must implement the {@link +android.app.Service#onBind onBind()} callback method to return an {@link android.os.IBinder} that +defines the interface for communication with the service. Other application components can then call +{@link android.content.Context#bindService bindService()} to retrieve the interface and +begin calling methods on the service. The service lives only to serve the application component that +is bound to it, so when there are no components bound to the service, the system destroys it +(you do <em>not</em> need to stop a bound service in the way you must when the service is started +through {@link android.app.Service#onStartCommand onStartCommand()}).</p> + +<p>To create a bound service, the first thing you must do is define the interface that specifies +how a client can communicate with the service. This interface between the service +and a client must be an implementation of {@link android.os.IBinder} and is what your service must +return from the {@link android.app.Service#onBind +onBind()} callback method. Once the client receives the {@link android.os.IBinder}, it can begin +interacting with the service through that interface.</p> + +<p>Multiple clients can bind to the service at once. When a client is done interacting with the +service, it calls {@link android.content.Context#unbindService unbindService()} to unbind. Once +there are no clients bound to the service, the system destroys the service.</p> + +<p>There are multiple ways to implement a bound service and the implementation is more +complicated than a started service, so the bound service discussion appears in a separate +document about <a +href="{@docRoot}guide/topics/fundamentals/bound-services.html">Bound Services</a>.</p> + + + +<h2 id="Notifications">Sending Notifications to the User</h2> + +<p>Once running, a service can notify the user of events using <a +href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a +href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>.</p> + +<p>A toast notification is a message that appears on the surface of the current window for a +moment then disappears, while a status bar notification provides an icon in the status bar with a +message, which the user can select in order to take an action (such as start an activity).</p> + +<p>Usually, a status bar notification is the best technique when some background work has completed +(such as a file completed +downloading) and the user can now act on it. When the user selects the notification from the +expanded view, the notification can start an activity (such as to view the downloaded file).</p> + +<p>See the <a +href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a +href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a> +developer guides for more information.</p> + + + +<h2 id="Foreground">Running a Service in the Foreground</h2> + +<p>A foreground service is a service that's considered to be something the +user is actively aware of and thus not a candidate for the system to kill when low on memory. A +foreground service must provide a notification for the status bar, which is placed under the +"Ongoing" heading, which means that the notification cannot be dismissed unless the service is +either stopped or removed from the foreground.</p> + +<p>For example, a music player that plays music from a service should be set to run in the +foreground, because the user it explicitly aware +of its operation. The notification in the status bar might indicate the current song and allow +the user to launch an activity to interact with the music player.</p> + +<p>To request that your service run in the foreground, call {@link +android.app.Service#startForeground startForeground()}. This method takes two parameters: an integer +that uniquely identifies the notification and the {@link +android.app.Notification} for the status bar. For example:</p> + +<pre> +Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), + System.currentTimeMillis()); +Intent notificationIntent = new Intent(this, ExampleActivity.class); +PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); +notification.setLatestEventInfo(this, getText(R.string.notification_title), + getText(R.string.notification_message), pendingIntent); +startForeground(ONGOING_NOTIFICATION, notification); +</pre> + + +<p>To remove the service from the foreground, call {@link +android.app.Service#stopForeground stopForeground()}. This method takes a boolean, indicating +whether to remove the status bar notification as well. This method does <em>not</em> stop the +service. However, if you stop the service while it's still running in the foreground, then the +notification is also removed.</p> + +<p class="note"><strong>Note:</strong> The methods {@link +android.app.Service#startForeground startForeground()} and {@link +android.app.Service#stopForeground stopForeground()} were introduced in Android 2.0 (API Level +5). In order to run your service in the foreground on older versions of the platform, you must +use the previous {@code setForeground()} method—see the {@link +android.app.Service#startForeground startForeground()} documentation for information about how +to provide backward compatibility.</p> + +<p>For more information about notifications, see <a +href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status Bar +Notifications</a>.</p> + + + +<h2 id="Lifecycle">Managing the Lifecycle of a Service</h2> + +<p>The lifecycle of a service is much simpler than that of an activity. However, it's even more important +that you pay close attention to how your service is created and destroyed, because a service +can run in the background without the user being aware.</p> + +<p>The service lifecycle—from when it's created to when it's destroyed—can follow two +different paths:</p> + +<ul> +<li>A started service + <p>The service is created when another component calls {@link +android.content.Context#startService startService()}. The service then runs indefinitely and must +stop itself by calling {@link +android.app.Service#stopSelf() stopSelf()}. Another component can also stop the +service by calling {@link android.content.Context#stopService +stopService()}. When the service is stopped, the system destroys it..</p></li> + +<li>A bound service + <p>The service is created when another component (a client) calls {@link +android.content.Context#bindService bindService()}. The client then communicates with the service +through an {@link android.os.IBinder} interface. The client can close the connection by calling +{@link android.content.Context#unbindService unbindService()}. Multiple clients can bind to +the same service and when all of them unbind, the system destroys the service. (The service +does <em>not</em> need to stop itself.)</p></li> +</ul> + +<p>These two paths are not entirely separate. That is, you can bind to a service that was already +started with {@link android.content.Context#startService startService()}. For example, a background +music service could be started by calling {@link android.content.Context#startService +startService()} with an {@link android.content.Intent} that identifies the music to play. Later, +possibly when the user wants to exercise some control over the player or get information about the +current song, an activity can bind to the service by calling {@link +android.content.Context#bindService bindService()}. In cases like this, {@link +android.content.Context#stopService stopService()} or {@link android.app.Service#stopSelf +stopSelf()} does not actually stop the service until all clients unbind. </p> + + +<h3 id="LifecycleCallbacks">Implementing the lifecycle callbacks</h3> + +<p>Like an activity, a service has lifecycle callback methods that you can implement to monitor +changes in the service's state and perform work at the appropriate times. The following skeleton +service demonstrates each of the lifecycle methods:</p> + + +<div class="figure" style="width:432px"> +<img src="{@docRoot}images/service_lifecycle.png" alt="" /> +<p class="img-caption"><strong>Figure 2.</strong> The service lifecycle. The diagram on the left +shows the lifecycle when the service is created with {@link android.content.Context#startService +startService()} and the diagram on the right shows the lifecycle when the service is created +with {@link android.content.Context#bindService bindService()}.</p> +</div> + +<pre> +public class ExampleService extends Service { + int mStartMode; // indicates how to behave if the service is killed + IBinder mBinder; // interface for clients that bind + boolean mAllowRebind; // indicates whether onRebind should be used + + @Override + public void {@link android.app.Service#onCreate onCreate}() { + // The service is being created + } + @Override + public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { + // The service is starting, due to a call to {@link android.content.Context#startService startService()} + return <em>mStartMode</em>; + } + @Override + public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()} + return <em>mBinder</em>; + } + @Override + public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { + // All clients have unbound with {@link android.content.Context#unbindService unbindService()} + return <em>mAllowRebind</em>; + } + @Override + public void {@link android.app.Service#onRebind onRebind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()}, + // after onUnbind() has already been called + } + @Override + public void {@link android.app.Service#onDestroy onDestroy}() { + // The service is no longer used and is being destroyed + } +} +</pre> + +<p class="note"><strong>Note:</strong> Unlike the activity lifecycle callback methods, you are +<em>not</em> required to call the superclass implementation of these callback methods.</p> + +<p>By implementing these methods, you can monitor two nested loops of the service's lifecycle: </p> + +<ul> +<li>The <strong>entire lifetime</strong> of a service happens between the time {@link +android.app.Service#onCreate onCreate()} is called and the time {@link +android.app.Service#onDestroy} returns. Like an activity, a service does its initial setup in +{@link android.app.Service#onCreate onCreate()} and releases all remaining resources in {@link +android.app.Service#onDestroy onDestroy()}. For example, a +music playback service could create the thread where the music will be played in {@link +android.app.Service#onCreate onCreate()}, then stop the thread in {@link +android.app.Service#onDestroy onDestroy()}. + +<p>The {@link android.app.Service#onCreate onCreate()} and {@link android.app.Service#onDestroy +onDestroy()} methods are called for all services, whether +they're created by {@link android.content.Context#startService startService()} or {@link +android.content.Context#bindService bindService()}.</p></li> + +<li>The <strong>active lifetime</strong> of a service begins with a call to either {@link +android.app.Service#onStartCommand onStartCommand()} or {@link android.app.Service#onBind onBind()}. +Each method is handed the {@link +android.content.Intent} that was passed to either {@link android.content.Context#startService +startService()} or {@link android.content.Context#bindService bindService()}, respectively. +<p>If the service is started, the active lifetime ends the same time that the entire lifetime +ends (the service is still active even after {@link android.app.Service#onStartCommand +onStartCommand()} returns). If the service is bound, the active lifetime ends when {@link +android.app.Service#onUnbind onUnbind()} returns.</p> +</li> +</ul> + +<p class="note"><strong>Note:</strong> Although a started service is stopped by a call to +either {@link android.app.Service#stopSelf stopSelf()} or {@link +android.content.Context#stopService stopService()}, there is not a respective callback for the +service (there's no {@code onStop()} callback). So, unless the service is bound to a client, +the system destroys it when the service is stopped—{@link +android.app.Service#onDestroy onDestroy()} is the only callback received.</p> + +<p>Figure 2 illustrates the typical callback methods for a service. Although the figure separates +services that are created by {@link android.content.Context#startService startService()} from those +created by {@link android.content.Context#bindService bindService()}, keep +in mind that any service, no matter how it's started, can potentially allow clients to bind to it. +So, a service that was initially started with {@link android.app.Service#onStartCommand +onStartCommand()} (by a client calling {@link android.content.Context#startService startService()}) +can still receive a call to {@link android.app.Service#onBind onBind()} (when a client calls +{@link android.content.Context#bindService bindService()}).</p> + +<p>For more information about creating a service that provides binding, see the <a +href="{@docRoot}guide/topics/fundamentals/bound-services.html">Bound Services</a> document, +which includes more information about the {@link android.app.Service#onRebind onRebind()} +callback method in the section about <a +href="{@docRoot}guide/topics/fundamentals/bound-services.html#Lifecycle">Managing the Lifecycle of +a Bound Service</a>.</p> + + + +<h2>Beginner's Path</h2> + +<p>To learn how to query data from the system or other applications (such as contacts or media +stored on the device), continue with the <b><a +href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b> +document.</p> diff --git a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd new file mode 100644 index 0000000..47dc547 --- /dev/null +++ b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd @@ -0,0 +1,568 @@ +page.title=Tasks and Back Stack +parent.title=Application Fundamentals +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>Quickview</h2> +<ul> + <li>All activities belong to a task</li> + <li>A task contains a collection of activities in the order in which the user interacts with +them</li> + <li>Tasks can move to the background and retain the state of each activity in order for the user +to perform other tasks without loosing their work</li> +</ul> + +<h2>In this document</h2> +<ol> +<li><a href="#ActivityState">Saving Activity State</a></li></li> +<li><a href="#ManagingTasks">Managing Tasks</a> + <ol> + <li><a href="#TaskLaunchModes">Defining launch modes</a></li> + <li><a href="#Affinities">Handling affinities</a></li> + <li><a href="#Clearing">Clearing the back stack</a></li> + <li><a href="#Starting">Starting a task</a></li> + </ol> +</li> +</ol> + +<h2>See also</h2> +<ol> + <li><a><a href="{@docRoot}videos/index.html#v=fL6gSd4ugSI">Application Lifecycle video</a></li> + <li><a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>} manifest +element</a></li> +</ol> +</div> +</div> + + +<p>An application usually contains multiple <a +href="{@docRoot}guide/topics/fundamentals/activities.html">activities</a>. Each activity +should be designed around a specific kind of action the user can perform and can start other +activities. For example, an email application might have one activity to show a list of new email. +When the user selects an email, a new activity opens to view that email.</p> + +<p>An activity can even start activities that exist in other applications on the device. For +example, if your application wants to send an email, you can define an intent to perform a "send" +action and include some data, such as an email address and a message. An activity from another +application that declares itself to handle this kind of intent then opens. In this case, the intent +is to send an email, so an email application's "compose" activity starts (if multiple activities +support the same intent, then the system lets the user select which one to use). When the email is +sent, your activity resumes and it seems as if the email activity was part of your application. Even +though the activities may be from different applications, Android maintains this seamless user +experience by keeping both activities in the same <em>task</em>.</p> + +<p>A task is a collection of activities that users interact with +when performing a certain job. The activities are arranged in a stack (the "back stack"), in the +order in which each activity is opened.</p> + +<!-- SAVE FOR WHEN THE FRAGMENT DOC IS ADDED +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h3>Adding fragments to a task's back stack</h3> + +<p>Your activity can also include {@link android.app.Fragment}s to the back stack. For example, +suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the +other being a layout to display an item from the list (fragment B). When the user selects an item +from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be +desireable for the user to navigate back to reveal fragment B, using the BACK key.</p> +<p>In order to add fragment B to the back stack so that this is possible, you must call {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link +android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment +C.</p> +<p>For more information about using fragments and adding them to the back stack, see the {@link +android.app.Fragment} class documentation.</p> + +</div> +</div> +--> + +<p>The device Home screen is the starting place for most tasks. When the user touches an icon in the +application +launcher (or a shortcut on the Home screen), that application's task comes to the foreground. If no +task exists for the application (the application has not been used recently), then a new task +is created and the "main" activity for that application opens as the root activity in the stack.</p> + +<p>When the current activity starts another, the new activity is pushed on the top of the stack and +takes focus. The previous activity remains in the stack, but is stopped. When an activity +stops, the system retains the current state of its user interface. When the user presses the BACK +key, the current activity is popped from the top of the stack (the activity is destroyed) and the +previous activity resumes (the previous state of its UI is restored). Activities in the stack are +never rearranged, only pushed and popped from the stack—pushed onto the stack when started by +the current activity and popped off when the user leaves it using the BACK key. As such, the back +stack operates as a "last in, first out" object structure. Figure 1 visualizes +this behavior with a timeline showing the progress between activities along with the current back +stack at each point in time.</p> + +<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> A representation of how each new activity in a +task adds an item to the back stack. When the user presses the BACK key, the current activity is +destroyed and the previous activity resumes.</p> + + +<p>If the user continues to press BACK, then each activity in the stack is popped off to reveal the +previous one, until the user returns to the Home screen (or to whichever activity was running when +the task began). When all activities are removed from the stack, the task no longer exists.</p> + +<div class="figure" style="width:369px"> +<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p +class="img-caption"><strong>Figure 2.</strong> Two tasks: Task A is in the background, waiting +to be resumed, while Task B receives user interaction in the foreground.</p> +</div> +<div class="figure" style="width:178px"> + <img src="{@docRoot}images/fundamentals/diagram_multiple_instances.png" alt="" /> <p +class="img-caption"><strong>Figure 3.</strong> A single activity is instantiated multiple times.</p> +</div> + +<p>A task is a cohesive unit that can move to the "background" when users begin a new task or go +to the Home screen, via the HOME key. While in the background, all the activities in the task are +stopped, but the back stack for the task remains intact—the task has simply lost focus while +another task takes place, as shown in figure 2. A task can then return to the "foreground" so users +can pick up where they left off. Suppose, for example, that the current task (Task A) has three +activities in its stack—two under the current activity. The user presses the HOME key, then +starts a new application from the application launcher. When the Home screen appears, Task A goes +into the background. When the new application starts, the system starts a task for that application +(Task B) with its own stack of activities. After interacting with +that application, the user returns Home again and selects the application that originally +started Task A. Now, Task A comes to the +foreground—all three activities in its stack are intact and the activity at the top of the +stack resumes. At +this point, the user can also switch back to Task B by going Home and selecting the application icon +that started that task (or by touching and holding the HOME key to reveal recent tasks and selecting +one). This is an example of multitasking on Android.</p> + +<p class="note"><strong>Note:</strong> Multiple tasks can be held in the background at once. +However, if the user is running many background tasks at the same time, the system might begin +destroying background activities in order to recover memory, causing the activity states to be lost. +See the following section about <a href="#ActivityState">Activity state</a>.</p> + +<p>Because the activities in the back stack are never rearranged, if your application allows +users to start a particular activity from more than one activity, a new instance of +that activity is created and popped onto the stack (rather than bringing any previous instance of +the activity to the top). As such, one activity in your application might be instantiated multiple +times (even from different tasks), as shown in figure 3. As such, if the user navigates backward +using the BACK key, each instance of the activity is revealed in the order they were opened (each +with their own UI state). However, you can modify this behavior if you do not want an activity to be +instantiated more than once. How to do so is discussed in the later section about <a +href="#ManagingTasks">Managing Tasks</a>.</p> + + +<p>To summarize the default behavior for activities and tasks:</p> + +<ul> + <li>When Activity A starts Activity B, Activity A is stopped, but the system retains its state +(such as scroll position and text entered into forms). +If the user presses the BACK key while in Activity B, Activity A resumes with its state +restored.</li> + <li>When the user leaves a task by pressing the HOME key, the current activity is stopped and +its task goes into the background. The system retains the state of every activity in the task. If +the user later resumes the task by selecting the launcher icon that began the task, the task comes +to the foreground and resumes the activity at the top of the stack.</li> + <li>If the user presses the BACK key, the current activity is popped from the stack and +destroyed. The previous activity in the stack is resumed. When an activity is destroyed, the system +<em>does not</em> retain the activity's state.</li> + <li>Activities can be instantiated multiple times, even from other tasks.</li> +</ul> + + +<h2 id="ActivityState">Saving Activity State</h2> + +<p>As discussed above, the system's default behavior preserves the state of an activity when it is +stopped. This way, when users navigate back to a previous activity, its user interface appears +the way they left it. However, you can—and <strong>should</strong>—proactively retain +the state of your activities using callback methods, in case the activity is destroyed and must +be recreated.</p> + +<p>When the system stops one of your activities (such as when a new activity starts or the task +moves to the background), the system might destroy that activity completely if it needs to recover +system memory. When this happens, information about the activity state is lost. If this happens, the +system still +knows that the activity has a place in the back stack, but when the activity is brought to the +top of the stack the system must recreate it (rather than resume it). In order to +avoid loosing the user's work, you should proactively retain it by implementing the {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} callback +methods in your activity.</p> + +<p>For more information about how to save your activity state, see the <a +href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">Activities</a> +document.</p> + + + +<h2 id="ManagingTasks">Managing Tasks</h2> + +<p>The way Android manages tasks and the back stack, as described above—by placing all +activities started in succession in the same task and in a "last in, first out" stack—works +great for most applications and you shouldn't have to worry about how your activities are associated +with tasks or how they exist in the back stack. However, you might decide that you want to interrupt +the normal behavior. Perhaps you want an activity in your application to begin a new task when it is +started (instead of being placed within the current task); or, when you start an activity, you want +to bring forward an existing instance of it (instead of creating a new +instance on top of the back stack); or, you want your back stack to be cleared of all +activitiesstart an activity except for the root activity when the user leaves the task.</p> + +<p>You can do these things and more, with attributes in the +<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a> manifest element and with flags in the intent that you pass to {@link +android.app.Activity#startActivity startActivity()}.</p> + +<p>In this regard, the the principal <a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> +attributes you can use are:</p> + +<ul class="nolist"> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code +taskAffinity}</a></li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code +launchMode}</a></li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">{@code +allowTaskReparenting}</a></li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code +clearTaskOnLaunch}</a></li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#always">{@code +alwaysRetainTaskState}</a></li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code +finishOnTaskLaunch}</a></li> +</ul> + +<p>And the principal intent flags you can use are:</p> + +<ul class="nolist"> + <li>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</li> + <li>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</li> + <li>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</li> +</ul> + +<p>In the following sections, you'll see how you can use these manifest attributes and intent +flags to define how activities are associated with tasks and how the behave in the back stack.</p> + + +<p class="caution"><strong>Caution:</strong> Most applications should not interrupt the default +behavior for activities and tasks. If you determine that it's necessary for your activity to modify +the default behaviors, use caution and be sure to test the usability of the activity during +launch and when navigating back to it from other activities and tasks with the BACK key. Be sure +to test for navigation behaviors that might conflict with the user's expected behavior.</p> + + +<h3 id="TaskLaunchModes">Defining launch modes</h3> + +<p>Launch modes allow you to define how a new instance of an activity is associated with the +current task. You can define different launch modes in two ways:</p> +<ul class="nolist"> + <li><a href="#ManifestForTasks">Using the manifest file</a> + <p>When you declare an activity in your manifest file, you can specify how the activity +should associate with tasks when it starts.</li> + <li><a href="#IntentFlagsForTasks">Using Intent flags</a> + <p>When you call {@link android.app.Activity#startActivity startActivity()}, +you can include a flag in the {@link android.content.Intent} that declares how (or +whether) the new activity should associate with the current task.</p></li> +</ul> + +<p>As such, if Activity A starts Activity B, Activity B can define in its manifest how it +should associate with the current task (if at all) and Activity A can also request how Activity +B should associate with current task. If both activities define how Activity B +should associate with a task, then Activity A's request (as defined in the intent) is honored +over Activity B's request (as defined in its manifest).</p> + +<p class="note"><strong>Note:</strong> Some the launch modes available in the manifest +are not available as flags for an intent and, likewise, some launch modes available as flags +for an intent cannot be defined in the manifest.</p> + + +<h4 id="ManifestForTasks">Using the manifest file</h4> + +<p>When declaring an activity in your manifest file, you can specify how the activity should +associate with a task using the <a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> +element's <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code +launchMode}</a> attribute.</p> + +<p>The <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code +launchMode}</a> attribute specifies an instruction on how the activity should be launched into a +task. There are four different launch modes you can assign to the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code> +attribute:</p> + +<dl> +<dt>{@code "standard"} (the default mode)</dt> + <dd>Default. The system creates a new instance of the activity in the task from +which it was started and routes the intent to it. The activity can be instantiated multiple times, +each instance can belong to different tasks, and one task can have multiple instances.</dd> +<dt>{@code "singleTop"}</dt> + <dd>If an instance of the activity already exists at the top of the current task, the system +routes the intent to that instance through a call to its {@link +android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a new instance of the +activity. The activity can be instantiated multiple times, each instance can +belong to different tasks, and one task can have multiple instances (but only if the the +activity at the top of the back stack is <em>not</em> an existing instance of the activity). + <p>For example, suppose a task's back stack consists of root activity A with activities B, C, +and D on top (the stack is A-B-C-D; D is on top). An intent arrives for an activity of type D. +If D has the default {@code "standard"} launch mode, a new instance of the class is launched and the +stack becomes A-B-C-D-D. However, if D's launch mode is {@code "singleTop"}, the existing instance +of D is deliverd the intent through {@link +android.app.Activity#onNewIntent onNewIntent()}, because it's at the top of the stack—the +stack remains A-B-C-D. However, if an intent arrives for an activity of type B, then a new +instance of B is added to the stack, even if its launch mode is {@code "singleTop"}.</p> + <p class="note"><strong>Note:</strong> When a new instance of an activity is created, +the user can press the BACK key to return to the previous activity. But when an existing instance of +an activity handles a new intent, the user cannot press the BACK key to return to the state of +the activity before the new intent arrived in {@link android.app.Activity#onNewIntent +onNewIntent()}.</p> +</dd> + +<dt>{@code "singleTask"}</dt> + <dd>The system creates a new task and instantiates the activity at the root of the new task. +However, if an instance of the activity already exists in a separate task, the system routes the +intent to the existing instance through a call to its {@link +android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a new instance. Only +one instance of the activity can exist at a time. + <p class="note"><strong>Note:</strong> Although the activity starts in a new task, the +BACK key still returns the user to the previous activity.</p></dd> +<dt>{@code "singleInstance"}.</dt> + <dd>Same as {@code "singleTask"}, except that the system doesn't launch any other activities into +the task holding the instance. The activity is always the single and only member of its task; +any activities started by this one open in a separate task.</dd> +</dl> + + +<p>As another example, the Android Browser application declares that the web browser activity should +always open in its own task—by specifying the {@code singleTask} launch mode in the <a +href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element. +This means that if your application issues an +intent to open the Android Browser, its activity is <em>not</em> placed in the same +task as your application. Instead, either a new task starts for the Browser or, if the Browser +already has a task running in the background, that task is brought forward to handle the new +intent.</p> + +<p>Regardless of whether an activity starts in a new task or in the same task as the activity that +started it, the BACK key always takes the user to the previous activity. However, if you +start an activity from your task (Task A) that specifies the {@code singleTask} launch mode, then +that activity might have an instance in the background that belongs to a task with its own back +stack (Task B). In this +case, when Task B is brought forward to handle a new intent, the BACK key first navigates +backward through the activities in Task B before returning to +the top-most activity in Task A. Figure 4 visualizes this type of scenario.</p> + +<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" /> +<p class="img-caption"><strong>Figure 4.</strong> A representation of how an activity with +launch mode "singleTask" is added to the back stack. If the activity is already a part of a +background task with its own back stack (Task B), then the entire back stack also comes +forward, on top of the current task (Task A).</p> + +<p>For more information about using launch modes in the manifest file, see the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> +element documentation, where the {@code launchMode} attribute and the accepted values are +discussed more.</p> + +<p class="note"><strong>Note:</strong> The behaviors that you specify for your activity with the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> attribute +can be overriden by flags included with the intent that start your activity, as discussed in the +next section.</p> + + + +<h4 id="#IntentFlagsForTasks">Using Intent flags</h4> + +<p>When starting an activity, you can modify the default association of an activity to its task +by including flags in the intent that you deliver to {@link +android.app.Activity#startActivity startActivity()}. The flags you can use to modify the +default behavior are:</p> + +<p> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt> + <dd>Start the activity in a new task. If a task is already running for the activity you are now +starting, that task is brought to the foreground with its last state restored and the activity +receives the new intent in {@link android.app.Activity#onNewIntent onNewIntent()}. + <p>This produces the same behavior as the {@code "singleTask"} <a +href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> value, +discussed in the previous section.</p></dd> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</dt> + <dd>If the activity being started is the current activity (at the top of the back stack), then +the existing instance receives a call to {@link android.app.Activity#onNewIntent onNewIntent()}, +instead of creating a new instance of the activity. + <p>This produces the same behavior as the {@code "singleTop"} <a +href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> value, +discussed in the previous section.</p></dd> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</dt> + <dd>If the activity being started is already running in the current task, then instead +of launching a new instance of that activity, all of the other activities on top of it are +destroyed and this intent is delivered to the resumed instance of the activity (now on top), +through {@link android.app.Activity#onNewIntent onNewIntent()}). + <p>There is no value for the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> +attribute that produces this behavior.</p> + <p>{@code FLAG_ACTIVITY_CLEAR_TOP} is most often used in conjunction with {@code +FLAG_ACTIVITY_NEW_TASK}. When used together, these flags are a way of locating an existing activity +in another task and putting it in a position where it can respond to the intent. </p> + <p class="note"><strong>Note:</strong> If the launch mode of the designated activity is {@code +"standard"}, it too is removed from the stack and a new instance is launched in its place to handle +the incoming intent. That's because a new instance is always created for a new intent when the +launch mode is {@code "standard"}. </p> +</dd> +</dl> + + + + + +<h3 id="Affinities">Handling affinities</h3> + +<p>The <em>affinity</em> indicates which task an activity prefers to belong to. By default, all the +activities from the same application have an affinity for each other. So, by default, all +activities in the same application prefer to be in the same task. However, you can modify +the default affinity for an activity. Activities defined in +different applications can share an affinity, or activities defined in the same application can be +assigned different task affinities.</p> + +<p>You can modify the affinity for any given activity with the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> attribute +of the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> +element.</p> + +<p>The <a +href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> +attribute takes a string value, which must be unique from the default package name +declared in the <a href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code +<manifest>}</a> element, because the system uses that name to identify the default task +affinity for the application.</p> + +<p>The affinity comes into play in two circumstances:</p> +<ul> + <li>When the intent that launches an activity contains the {@link +android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag. + +<p>A new activity is, by default, launched into the task of the activity +that called {@link android.app.Activity#startActivity startActivity()}. It's pushed onto the same +back stack as the caller. However, if the intent passed to {@link +android.app.Activity#startActivity startActivity()} contains the {@link +android.content.Intent#FLAG_ACTIVITY_NEW_TASK} +flag, the system looks for a different task to house the new activity. Often, it's a new task. +However, it doesn't have to be. If there's already an existing task with the same affinity as the +new activity, the activity is launched into that task. If not, it begins a new task.</p> + +<p>If this flag causes an activity to begin a new task and the user presses the HOME key to leave +it, there must be some way for the user to navigate back to the task. Some entities (such as the +notification manager) always start activities in an external task, never as part of their own, so +they always put {@code FLAG_ACTIVITY_NEW_TASK} in the intents they pass to {@link +android.app.Activity#startActivity startActivity()}. If you have an activity that can be invoked by +an external entity that might use this flag, take care that the user has a independent way to get +back to the task that's started, such as with a launcher icon (the root activity of the task +has a {@link android.content.Intent#CATEGORY_LAUNCHER} intent filter; see the <a +href="#Starting">Starting a task</a> section below).</p> +</li> + + <li>When an activity has its <a +href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">{@code +allowTaskReparenting}</a> attribute set to {@code "true"}. + <p>In this case, the activity can move from the task it starts to the task it has an affinity +for, when that task comes to the foreground.</p> + <p>For example, suppose that an activity that reports weather conditions in selected cities is +defined as part of a travel application. It has the same affinity as other activities in the same +application (the default application affinity) and it allows re-parenting with this attribute. +When one of your activities starts the weather reporter activity, it initially belongs to the same +task as your activity. However, when the travel application's task comes to the foreground, the +weather reporter activity is reassigned to that task and displayed within it.</p> +</li> +</ul> + +<p class="note"><strong>Tip:</strong> If an {@code .apk} file contains more than one "application" +from the user's point of view, you probably want to use the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> +attribute to assign different affinities to the activities associated with each "application".</p> + + + +<h3 id="Clearing">Clearing the back stack</h3> + +<p>If the user leaves a task for a long time, the system clears the task of all activities except +the root activity. When the user returns to the task again, only the root activity is restored. +The system behaves this way, because, after an extended amount of time, users likely have abandoned +what they were doing before and are returning to the task to begin something new. </p> + +<p>There are some activity attributes that you can use to modify this behavior: </p> + +<dl> +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code> +</dt> +<dd>If this attribute is set to {@code "true"} in the root activity of a task, +the default behavior just described does not happen. +The task retains all activities in its stack even after a long period.</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt> +<dd>If this attribute is set to {@code "true"} in the root activity of a task, +the stack is cleared down to the root activity whenever the user leaves the task +and returns to it. In other words, it's the opposite of <a +href="{@docRoot}guide/topics/manifest/activity-element.html#always">{@code +alwaysRetainTaskState}</a>. The user always returns to the task in its +initial state, even after a leaving the task for only a moment.</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code> +</dt> +<dd>This attribute is like <a +href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code clearTaskOnLaunch}</a>, +but it operates on a +single activity, not an entire task. It can also cause any activity to go +away, including the root activity. When it's set to {@code "true"}, the +activity remains part of the task only for the current session. If the user +leaves and then returns to the task, it is no longer present.</dd> +</dl> + + + + +<h3 id="Starting">Starting a task</h3> + +<p>You can set up an activity as the entry point for a task by giving it an intent filter with +{@code "android.intent.action.MAIN"} as the specified action and {@code +"android.intent.category.LAUNCHER"} as the specified category. For example:</p> + +<pre> +<activity ... > + <intent-filter ... > + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + ... +</activity> +</pre> + +<p>An intent filter of this kind causes an icon and label for the +activity to be displayed in the application launcher, giving users a way to launch the activity and +to return to the task that it creates any time after it has been launched. +</p> + +<p>This second ability is important: Users must be able to leave a task and then come back to it +later using this activity launcher. For this reason, the two <a href="#LaunchModes">launch +modes</a> that mark activities as always initiating a task, {@code "singleTask"} and "{@code +"singleInstance"}, should be used only when the activity has an {@link +android.content.Intent#ACTION_MAIN} +and a {@link android.content.Intent#CATEGORY_LAUNCHER} +filter. Imagine, for example, what could happen if the filter is missing: An intent launches a +{@code "singleTask"} activity, initiating a new task, and the user spends some time working in +that task. The user then presses the HOME key. The task is now sent to the background and not +visible. Because it is not represented in the application launcher, the user has no way to return to +the task. +</p> + +<p>For those cases where you don't want the user to be able to return to an activity, set the + <code><a +href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> element's +<a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code +finishOnTaskLaunch}</a> to {@code "true"} (see <a +href="#Clearing">Clearing the stack</a>).</p> + + + + +<h2>Beginner's Path</h2> + +<p>For more information about how to use intents to +activate other application components and publish the intents to which your components +respond, continue with the <b><a +href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent +Filters</a></b> document.</p> diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd index 13a86dd..6594568 100644 --- a/docs/html/guide/topics/graphics/2d-graphics.jd +++ b/docs/html/guide/topics/graphics/2d-graphics.jd @@ -17,8 +17,6 @@ parent.link=index.html <li><a href="#shape-drawable">Shape Drawable</a></li> <!-- <li><a href="#state-list">StateListDrawable</a></li> --> <li><a href="#nine-patch">Nine-patch</a></li> - <li><a href="#tween-animation">Tween Animation</a></li> - <li><a href="#frame-animation">Frame Animation</a></li> </ol> </div> </div> @@ -61,7 +59,7 @@ extension (E.g., <code>my_image.png</code> is referenced as <var>my_image</var>) <p class="note"><strong>Note:</strong> Image resources placed in <code>res/drawable/</code> may be automatically optimized with lossless image compression by the -<a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG that does +<code>aapt</code> tool during the build process. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If you plan on reading @@ -262,9 +260,9 @@ and saved into the <code>res/drawable/</code> directory of your project. <p> The border is used to define the stretchable and static areas of the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide - black line(s) in the left and top part of the border. (You can have as - many stretchable sections as you want.) The relative size of the stretchable - sections stays the same, so the largest sections always remain the largest. + black line(s) in the left and top part of the border (the other border pixels should + be fully transparent or white). You can have as many stretchable sections as you want: + their relative size stays the same, so the largest sections always remain the largest. </p> <p> You can also define an optional drawable section of the image (effectively, @@ -328,172 +326,4 @@ Notice how the width and height of the button varies with the text, and the back stretches to accommodate it. </p> -<img src="{@docRoot}images/ninepatch_examples.png" alt=""/> - - -<h2 id="tween-animation">Tween Animation</h2> - -<p>A tween animation can perform a series of simple transformations (position, size, rotation, and transparency) on -the contents of a View object. So, if you have a TextView object, you can move, rotate, grow, or shrink the text. -If it has a background image, the background image will be transformed along with the text. -The {@link android.view.animation animation package} provides all the classes used in a tween animation.</p> - -<p>A sequence of animation instructions defines the tween animation, defined by either XML or Android code. -Like defining a layout, an XML file is recommended because it's more readable, reusable, and swappable -than hard-coding the animation. In the example below, we use XML. (To learn more about defining an animation -in your application code, instead of XML, refer to the -{@link android.view.animation.AnimationSet} class and other {@link android.view.animation.Animation} subclasses.)</p> - -<p>The animation instructions define the transformations that you want to occur, when they will occur, -and how long they should take to apply. Transformations can be sequential or simultaneous — -for example, you can have the contents of a TextView move from left to right, and then -rotate 180 degrees, or you can have the text move and rotate simultaneously. Each transformation -takes a set of parameters specific for that transformation (starting size and ending size -for size change, starting angle and ending angle for rotation, and so on), and -also a set of common parameters (for instance, start time and duration). To make -several transformations happen simultaneously, give them the same start time; -to make them sequential, calculate the start time plus the duration of the preceding transformation. -</p> - -<p>The animation XML file belongs in the <code>res/anim/</code> directory of your Android project. -The file must have a single root element: this will be either a single <code><alpha></code>, -<code><scale></code>, <code><translate></code>, <code><rotate></code>, interpolator element, -or <code><set></code> element that holds groups of these elements (which may include another -<code><set></code>). By default, all animation instructions are applied simultaneously. -To make them occur sequentially, you must specify the <code>startOffset</code> attribute, as shown in the example below. -</p> - -<p>The following XML from one of the ApiDemos is used to stretch, -then simultaneously spin and rotate a View object. -</p> -<pre> -<set android:shareInterpolator="false"> - <scale - android:interpolator="@android:anim/accelerate_decelerate_interpolator" - android:fromXScale="1.0" - android:toXScale="1.4" - android:fromYScale="1.0" - android:toYScale="0.6" - android:pivotX="50%" - android:pivotY="50%" - android:fillAfter="false" - android:duration="700" /> - <set android:interpolator="@android:anim/decelerate_interpolator"> - <scale - android:fromXScale="1.4" - android:toXScale="0.0" - android:fromYScale="0.6" - android:toYScale="0.0" - android:pivotX="50%" - android:pivotY="50%" - android:startOffset="700" - android:duration="400" - android:fillBefore="false" /> - <rotate - android:fromDegrees="0" - android:toDegrees="-45" - android:toYScale="0.0" - android:pivotX="50%" - android:pivotY="50%" - android:startOffset="700" - android:duration="400" /> - </set> -</set> -</pre> -<p>Screen coordinates (not used in this example) are (0,0) at the upper left hand corner, -and increase as you go down and to the right.</p> - -<p>Some values, such as pivotX, can be specified relative to the object itself or relative to the parent. -Be sure to use the proper format for what you want ("50" for 50% relative to the parent, or "50%" for 50% -relative to itself).</p> - -<p>You can determine how a transformation is applied over time by assigning an -{@link android.view.animation.Interpolator}. Android includes -several Interpolator subclasses that specify various speed curves: for instance, -{@link android.view.animation.AccelerateInterpolator} tells -a transformation to start slow and speed up. Each one has an attribute value that can be applied in the XML.</p> - -<p>With this XML saved as <code>hyperspace_jump.xml</code> in the <code>res/anim/</code> directory of the -project, the following Java code will reference it and apply it to an {@link android.widget.ImageView} object -from the layout. -</p> -<pre> -ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage); -Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); -spaceshipImage.startAnimation(hyperspaceJumpAnimation); -</pre> - -<p>As an alternative to <code>startAnimation()</code>, you can define a starting time for the animation with -<code>{@link android.view.animation.Animation#setStartTime(long) Animation.setStartTime()}</code>, -then assign the animation to the View with -<code>{@link android.view.View#setAnimation(android.view.animation.Animation) View.setAnimation()}</code>. -</p> - -<p>For more information on the XML syntax, available tags and attributes, see <a -href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p> - -<p class="note"><strong>Note:</strong> Regardless of how your animation may move or resize, the bounds of the -View that holds your animation will not automatically adjust to accommodate it. Even so, the animation will still -be drawn beyond the bounds of its View and will not be clipped. However, clipping <em>will occur</em> -if the animation exceeds the bounds of the parent View.</p> - - -<h2 id="frame-animation">Frame Animation</h2> - -<p>This is a traditional animation in the sense that it is created with a sequence of different -images, played in order, like a roll of film. The {@link android.graphics.drawable.AnimationDrawable} -class is the basis for frame animations.</p> - -<p>While you can define the frames of an animation in your code, using the -{@link android.graphics.drawable.AnimationDrawable} class API, it's more simply accomplished with a single XML -file that lists the frames that compose the animation. Like the tween animation above, the XML file for this kind -of animation belongs in the <code>res/drawable/</code> directory of your Android project. In this case, -the instructions are the order and duration for each frame of the animation.</p> - -<p>The XML file consists of an <code><animation-list></code> element as the root node and a series -of child <code><item></code> nodes that each define a frame: a drawable resource for the frame and the frame duration. -Here's an example XML file for a frame-by-frame animation:</p> -<pre> -<animation-list xmlns:android="http://schemas.android.com/apk/res/android" - android:oneshot="true"> - <item android:drawable="@drawable/rocket_thrust1" android:duration="200" /> - <item android:drawable="@drawable/rocket_thrust2" android:duration="200" /> - <item android:drawable="@drawable/rocket_thrust3" android:duration="200" /> -</animation-list> -</pre> - -<p>This animation runs for just three frames. By setting the <code>android:oneshot</code> attribute of the -list to <var>true</var>, it will cycle just once then stop and hold on the last frame. If it is set <var>false</var> then -the animation will loop. With this XML saved as <code>rocket_thrust.xml</code> in the <code>res/drawable/</code> directory -of the project, it can be added as the background image to a View and then called to play. Here's an example Activity, -in which the animation is added to an {@link android.widget.ImageView} and then animated when the screen is touched:</p> -<pre> -AnimationDrawable rocketAnimation; - -public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image); - rocketImage.setBackgroundResource(R.drawable.rocket_thrust); - rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); -} - -public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - rocketAnimation.start(); - return true; - } - return super.onTouchEvent(event); -} -</pre> -<p>It's important to note that the <code>start()</code> method called on the AnimationDrawable cannot be -called during the <code>onCreate()</code> method of your Activity, because the AnimationDrawable is not yet fully attached -to the window. If you want to play the animation immediately, without -requiring interaction, then you might want to call it from the -<code>{@link android.app.Activity#onWindowFocusChanged(boolean) onWindowFocusChanged()}</code> method in -your Activity, which will get called when Android brings your window into focus.</p> - -<p>For more information on the XML syntax, available tags and attributes, see <a -href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p> - +<img src="{@docRoot}images/ninepatch_examples.png" alt=""/>
\ No newline at end of file diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd new file mode 100644 index 0000000..83a4e1d --- /dev/null +++ b/docs/html/guide/topics/graphics/animation.jd @@ -0,0 +1,828 @@ +page.title=Animation +@jd:body + <div id="qv-wrapper"> + <div id="qv"> + <h2>In this document</h2> + + <ol> + <li> + <a href="#property-animation">Property Animation</a> + + <ol> + <li><a href="#value-animator">Animating with ValueAnimator</a></li> + + <li><a href="#object-animator">Animating with ObjectAnimator</a></li> + + <li><a href="#type-evaluator">Using a TypeEvaluator</a></li> + + <li><a href="#interpolators">Using interpolators</a></li> + + <li><a href="#keyframes">Specifying keyframes</a></li> + + <li><a href="#choreography">Choreographing multiple animations with AnimatorSet</a></li> + + <li><a href="#declaring-xml">Declaring animations in XML</a></li> + </ol> + </li> + + <li> + <a href="#view-animation">View Animation</a> + + <ol> + <li><a href="#tween-animation">Tween animation</a></li> + + <li><a href="#frame-animation">Frame animation</a></li> + </ol> + </li> + </ol> + + <h2>Key classes</h2> + + <ol> + <li><code><a href= + "/reference/android/animation/ValueAnimator.html">ValueAnimator</a></code></li> + + <li><code><a href= + "/reference/android/animation/ObjectAnimator.html">ObjectAnimator</a></code></li> + + <li><code><a href= + "/reference/android/animation/TypeEvaluator.html">TypeEvaluator</a></code></li> + </ol> + + <h2>Related samples</h2> + + <ol> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/index.html">API Demos</a></li> + </ol> + + </div> + </div> + + <p>The Android system provides a flexible animation system that allows you to animate + almost anything, either programmatically or declaratively with XML. There are two + animation systems that you can choose from: <a href="#property-animation">property + animation</a> and <a href="#view-animation">view animation</a>. You can use whichever + system that matches your needs, but use only one system for each object that you + are animating.</p> + + <h2 id="property-animation">Property Animation</h2> + + <p>Introduced in Android 3.0, the property animation system allows you to animate + object properties of any type. <code>int</code>, <code>float</code>, + and hexadecimal color values are supported by default. You can animate any other type by telling the + system how to calculate the values for that given type.</p> + + <p>The property animation system allows you to define many aspects of an animation, + such as:</p> + + <ul> + <li>Duration</li> + + <li>Repeat amount and behavior</li> + + <li>Type of time interpolation</li> + + <li>Animator sets to play animations together, sequentially, or after specified + delays</li> + + <li>Frame refresh delay</li> + + </ul> + + <p>Most of the property animation system's features can be found in + {@link android.animation android.animation}. Because the + <a href="#view-animation">view animation</a> system already + defines many interpolators in {@link android.view.animation android.view.animation}, + you will use those to define your animation's interpolation in the property animation + system as well. + </p> + + <p>The following items are the main components of the property animation system:</p> + + <dl> + <dt><strong>Animators</strong></dt> + + <dd> + The {@link android.animation.Animator} class provides the basic structure for + creating animations. You normally do not use this class directly as it only provides + minimal functionality that must be extended to fully support animating values. + The following subclasses extend {@link android.animation.Animator}, which you might find more useful: + + <ul> + <li>{@link android.animation.ValueAnimator} is the main timing engine for + property animation and computes the values for the property to be animated. + {@link android.animation.ValueAnimator} only computes the animation values and is + not aware of the specific object and property that is being animated or what the + values might be used for. You must listen for updates to values calculated by the + {@link android.animation.ValueAnimator} and process the data with your own logic. + See the section about <a href="#value-animator">Animating with ValueAnimator</a> + for more information.</li> + + <li>{@link android.animation.ObjectAnimator} is a subclass of {@link + android.animation.ValueAnimator} and allows you to set a target object and object + property to animate. This class is aware of the object and property to be + animated, and updates the property accordingly when it computes a new value for + the animation. See the section about <a href="#object-animator"> + Animating with ObjectAnimator</a> for more information.</li> + + <li>{@link android.animation.AnimatorSet} provides a mechanism to group + animations together so that they are rendered in relation to one another. You can + set animations to play together, sequentially, or after a specified delay. + See the section about <a href="#choreography"> + Choreographing multiple animations with Animator Sets</a> for more information.</li> + </ul> + </dd> + + <dt><strong>Evaluators</strong></dt> + + <dd> + <p>If you are animating an object property that is <em>not</em> an <code>int</code>, + <code>float</code>, or color, implement the {@link android.animation.TypeEvaluator} + interface to specify how to compute the object property's animated values. You give + a {@link android.animation.TypeEvaluator} the timing data that is provided by an + {@link android.animation.Animator} class, the animation's start and end value, and + provide logic that computes the animated values of the property based on this data.</p> + + <p>You can also specify a custom {@link android.animation.TypeEvaluator} for + <code>int</code>, <code>float</code>, and color values as well, if you want to + process those types differently than the default behavior.</p> + + <p>See <a href="#type-evaluator">Using a TypeEvaluator</a> for more information on + how to write a custom evaluator.</p> + </dd> + + <dt><strong>Interpolators</strong></dt> + + <dd> + <p>A time interpolator defines how specific values in an animation are calculated + as a function of time. For example, you can specify animations to happen linearly + across the whole animation, meaning the animation moves evenly the entire time, or + you can specify animations to use non-linear time, for example, using acceleration + or deceleration at the beginning or end of the animation.</p> + + <p>The Android system provides a set of common interpolators in + {@link android.view.animation android.view.animation}. If none of these suits your needs, you + can implement the {@link android.animation.TimeInterpolator} interface and create + your own. See <a href="#interpolators">Using interpolators</a> for more information on + how to write a custom interpolator.</p> + </dd> + </dl> + + + <p>The <code>com.example.android.apis.animation</code> package in the <a href= + "{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/index.html"> + API Demos</a> sample project also provides a good overview and many examples on how to + use the property animation system.</p> + + + <h3>How the property animation system calculates animated values</h3> + + <p>When you call {@link android.animation.ValueAnimator#start start()} to begin an animation, + the {@link android.animation.ValueAnimator} calculates + an <em>elapsed fraction</em> between 0 and 1, based on the duration of the animation + and how much time has elapsed. The elapsed fraction represents the percentage of time + that the animation has completed, 0 meaning 0% and 1 meaning 100%. The Animator then + calls the {@link android.animation.TimeInterpolator} that is currently set, + to calculate an <em>eased fraction</em>, + which is a modified value of the elapsed fraction that takes into account the interpolator that + is set (time interpolation is often referred to as <em>easing</em>). The eased fraction + is the final value that is used to animate the property.</p> + + <p>Once the eased fraction is calculated, {@link android.animation.ValueAnimator} calls + the appropriate {@link android.animation.TypeEvaluator} to calculate the final value of + the property that you are animating, based on the eased fraction, the starting value, + and ending value of the animation.</p> + + <h3 id="value-animator">Animating with ValueAnimator</h3> + + <p>The {@link android.animation.ValueAnimator} class lets you animate values of some + type for the duration of an animation by specifying a set of <code>int</code>, + <code>float</code>, or color values to animate over and the duration of the animation. + You obtain a {@link android.animation.ValueAnimator} by calling one of its factory + methods: {@link android.animation.ValueAnimator#ofInt ofInt()}, + {@link android.animation.ValueAnimator#ofFloat ofFloat()}, + or {@link android.animation.ValueAnimator#ofObject ofObject()}. For example:</p> + + <pre>ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); +animation.setDuration(1000); +animation.start(); +</pre> + + <p>In this code, the {@link android.animation.ValueAnimator} starts + calculating the values of the animation, between 0 and 1, for + a duration of 1000 ms, when the <code>start()</code> method runs.</p> + + <p>You can also specify a custom type to animate by doing the following:</p> + + <pre>ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue); +animation.setDuration(1000); +animation.start(); +</pre> + + <p>In this code, the {@link android.animation.ValueAnimator} starts + calculating the values of the animation, between <code>startPropertyValue</code> and + <code>endPropertyValue</code> using the logic supplied by <code>MyTypeEvaluator</code> + for a duration of 1000 ms, when the {@link android.animation.ValueAnimator#start start()} + method runs.</p> + + <p>The previous code snippets, however, do not affect an object, because the {@link + android.animation.ValueAnimator} does not operate on objects or properties directly. To + use the results of a {@link android.animation.ValueAnimator}, you must define listeners + in the {@link android.animation.ValueAnimator} to appropriately handle important events + during the animation's lifespan, such as frame updates. You can implement the following + interfaces to create listeners for {@link android.animation.ValueAnimator}:</p> + + <ul> + <li>{@link android.animation.Animator.AnimatorListener} + + <ul> + <li>{@link android.animation.Animator.AnimatorListener#onAnimationStart + onAnimationStart()} - Called when the animation starts</li> + + <li>{@link android.animation.Animator.AnimatorListener#onAnimationEnd + onAnimationEnd()} - Called when the animation ends.</li> + + <li>{@link android.animation.Animator.AnimatorListener#onAnimationRepeat + onAnimationRepeat()} - Called when the animation repeats itself.</li> + + <li>{@link android.animation.Animator.AnimatorListener#onAnimationCancel + onAnimationCancel()} - Called when the animation is canceled.</li> + </ul> + </li> + + <li>{@link android.animation.ValueAnimator.AnimatorUpdateListener} + + <ul> + <li> + <p>{@link + android.animation.ValueAnimator.AnimatorUpdateListener#onAnimationUpdate + onAnimationUpdate()} - called on every frame of the animation. + Listen to this event to use the calculated values generated by + {@link android.animation.ValueAnimator} during an animation. To use the value, + query the {@link android.animation.ValueAnimator} object passed into the event + to get the current animated value with the + {@link android.animation.ValueAnimator#getAnimatedValue getAnimatedValue()} method.</p> + + <p>If you are animating your own custom object (not View objects), this + callback must also call the {@link android.view.View#invalidate invalidate()} + method to force a redraw of the screen. If you are animating View objects, + {@link android.view.View#invalidate invalidate()} is automatically called when + a property of the View is changed.</p> + </li> + </ul> + + <p>You can extend the {@link android.animation.AnimatorListenerAdapter} class + instead of implementing the {@link android.animation.Animator.AnimatorListener} + interface, if you do not want to implement all of the methods of the {@link + android.animation.Animator.AnimatorListener} interface. The {@link + android.animation.AnimatorListenerAdapter} class provides empty implementations of the + methods that you can choose to override.</p> + </li> + </ul> + + <p>For example, the <a href= + "{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/BouncingBalls.html"> + Bouncing Balls</a> sample in the API demos creates an {@link + android.animation.AnimatorListenerAdapter} for just the {@link + android.animation.Animator.AnimatorListener#onAnimationEnd onAnimationEnd()} + callback:</p> + + <pre>ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); +fadeAnim.setDuration(250); +fadeAnim.addListener(new AnimatorListenerAdapter() { +public void onAnimationEnd(Animator animation) { + balls.remove(((ObjectAnimator)animation).getTarget()); +}</pre> + + <h3 id="object-animator">Animating with ObjectAnimator</h3> + + <p>The {@link android.animation.ObjectAnimator} is a subclass of the {@link + android.animation.ValueAnimator} (discussed in the previous section) + and combines the timing engine and value computation + of {@link android.animation.ValueAnimator} with the ability to animate a named property + of a target object. This makes animating any object much easier, as you no longer need + to implement the {@link android.animation.ValueAnimator.AnimatorUpdateListener}, because + the animated property updates automatically.</p> + + <p>Instantiating an {@link android.animation.ObjectAnimator} is similar to a {@link + android.animation.ValueAnimator}, but you also specify the object and that object's + property (as a String) that you want to animate:</p> + <pre>ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f); +anim.setDuration(1000); +anim.start();</pre> + + <p>To have the {@link android.animation.ObjectAnimator} update properties correctly, + you must do the following:</p> + + <ul> + <li>The object property that you are animating must have a setter function in the + form of <code>set<propertyName>()</code>. Because the {@link + android.animation.ObjectAnimator} automatically updates the property during + animation, it must be able to access the property with this setter method. For + example, if the property name is <code>foo</code>, you need to have a + <code>setFoo()</code> method. If this setter method does not exist, you have three + options: + + <ul> + <li>Add the setter method to the class if you have the rights to do so.</li> + + <li>Use a wrapper class that you have rights to change and have that wrapper + receive the value with a valid setter method and forward it to the original + object.</li> + + <li>Use {@link android.animation.ValueAnimator} instead.</li> + </ul> + </li> + + <li>If you specify only one value for the <code>values...</code> parameter, + in one of the {@link android.animation.ObjectAnimator} factory methods, it is assumed to be + the ending value of the animation. Therefore, the object property that you are + animating must have a getter function that is used to obtain the starting value of + the animation. The getter function must be in the form of + <code>get<propertyName>()</code>. For example, if the property name is + <code>foo</code>, you need to have a <code>getFoo()</code> method.</li> + + <li>The getter (if needed) and setter methods of the property that you are animating must + return the same type as the starting and ending values that you specify to {@link + android.animation.ObjectAnimator}. For example, you must have + <code>targetObject.setPropName(float)</code> and + <code>targetObject.getPropName(float)</code> if you construct the following {@link + android.animation.ObjectAnimator}: + <pre>ObjectAnimator.ofFloat(targetObject, "propName", 1f)</pre> + </li> + </ul> + + <h3 id="type-evaluator">Using a TypeEvaluator</h3> + + <p>If you want to animate a type that is unknown to the Android system, + you can create your own evaluator by implementing the {@link + android.animation.TypeEvaluator} interface. The types that are known by the Android + system are <code>int</code>, <code>float</code>, or a color, which are supported by the + {@link android.animation.IntEvaluator}, {@link android.animation.FloatEvaluator}, and + {@link android.animation.ArgbEvaluator} type evaluators.</p> + + <p>There is only one method to implement in the {@link android.animation.TypeEvaluator} + interface, the {@link android.animation.TypeEvaluator#evaluate evaluate()} method. + This allows the animator that you are using to return an + appropriate value for your animated property at the current point of the animation. The + {@link android.animation.FloatEvaluator} class demonstrates how to do this:</p> + <pre>public class FloatEvaluator implements TypeEvaluator { + + public Object evaluate(float fraction, Object startValue, Object endValue) { + float startFloat = ((Number) startValue).floatValue(); + return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); + } +}</pre> + + <p class="note"><strong>Note:</strong> When {@link android.animation.ValueAnimator} (or + {@link android.animation.ObjectAnimator}) runs, it calculates a current elapsed + fraction of the animation (a value between 0 and 1) and then calculates an eased + version of that depending on what interpolator that you are using. The eased fraction + is what your {@link android.animation.TypeEvaluator} receives through the <code>fraction</code> + parameter, so you do not have to take into account the interpolator + when calculating animated values.</p> + + <h3 id="interpolators">Using interpolators</h3> + + <p>An interpolator define how specific values in an animation are + calculated as a function of time. For example, you can specify animations to happen + linearly across the whole animation, meaning the animation moves evenly the entire + time, or you can specify animations to use non-linear time, for example, using + acceleration or deceleration at the beginning or end of the animation.</p> + + <p>Interpolators in the animation system receive a fraction from Animators that represent the elapsed time + of the animation. Interpolators modify this fraction to coincide with the type of + animation that it aims to provide. The Android system provides a set of common + interpolators in the {@link android.view.animation android.view.animation package}. If + none of these suit your needs, you can implement the {@link + android.animation.TimeInterpolator} interface and create your own.</p> + + <p>As an example, how the default interpolator {@link + android.view.animation.AccelerateDecelerateInterpolator} and the {@link + android.view.animation.LinearInterpolator} calculate eased fractions are compared below. The {@link + android.view.animation.LinearInterpolator} has no effect on the elapsed fraction, + because a linear interpolation is calculated the same way as the elapsed fraction. The + {@link android.view.animation.AccelerateDecelerateInterpolator} accelerates into the + animation and decelerates out of it. The following methods define the logic for these + interpolators:</p> + + <p><strong>AccelerateDecelerateInterpolator</strong></p> + <pre>public float getInterpolation(float input) { + return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; +}</pre> + + <p><strong>LinearInterpolator</strong></p> + <pre>public float getInterpolation(float input) { + return input; +}</pre> + + <p>The following table represents the approximate values that are calculated by these + interpolators for an animation that lasts 1000ms:</p> + + <table> + <tr> + <th>ms elapsed</th> + + <th>Elapsed fraction/Eased fraction (Linear)</th> + + <th>Eased fraction (Accelerate/Decelerate)</th> + </tr> + + <tr> + <td>0</td> + + <td>0</td> + + <td>0</td> + </tr> + + <tr> + <td>200</td> + + <td>.2</td> + + <td>.1</td> + </tr> + + <tr> + <td>400</td> + + <td>.4</td> + + <td>.345</td> + </tr> + + <tr> + <td>600</td> + + <td>.6</td> + + <td>.8</td> + </tr> + + <tr> + <td>800</td> + + <td>.8</td> + + <td>.9</td> + </tr> + + <tr> + <td>1000</td> + + <td>1</td> + + <td>1</td> + </tr> + </table> + + <p>As the table shows, the {@link android.view.animation.LinearInterpolator} changes + the values at the same speed, .2 for every 200ms that passes. The {@link + android.view.animation.AccelerateDecelerateInterpolator} changes the values faster than + {@link android.view.animation.LinearInterpolator} between 200ms and 600ms and slower + between 600ms and 1000ms.</p> + + <h3 id="keyframes">Specifying keyframes</h3> + + <p>A {@link android.animation.Keyframe} object consists of a time/value pair that lets + you define a specific state at a specific time of an animation. Each keyframe can also + have its own interpolator to control the behavior of the animation in the interval + between the previous keyframe's time and the time of this keyframe.</p> + + <p>To instantiate a {@link android.animation.Keyframe} object, you must use one of the + factory methods, {@link android.animation.Keyframe#ofInt ofInt()}, {@link + android.animation.Keyframe#ofFloat ofFloat()}, or {@link + android.animation.Keyframe#ofObject ofObject()} to obtain the appropriate type of + {@link android.animation.Keyframe}. You then call the {@link + android.animation.PropertyValuesHolder#ofKeyframe ofKeyframe()} factory method to + obtain a {@link android.animation.PropertyValuesHolder} object. Once you have the + object, you can obtain an animator by passing in the {@link + android.animation.PropertyValuesHolder} object and the object to animate. The following + code snippet demonstrates how to do this:</p> + <pre>Keyframe kf0 = Keyframe.ofFloat(0f, 0f); +Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f); +Keyframe kf2 = Keyframe.ofFloat(1f, 0f); +PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2); +ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation) +rotationAnim.setDuration(5000ms); +</pre> +<p>For a more complete example on how to use keyframes, see the <a href= +"{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/MultiPropertyAnimation.html"> + MultiPropertyAnimation</a> sample in APIDemos.</p> + + <h3 id="choreography">Choreographing multiple animations with AnimatorSet</h3> + + <p>In many cases, you want to play an animation that depends on when another animation + starts or finishes. The Android system lets you bundle animations together into an + {@link android.animation.AnimatorSet}, so that you can specify whether to start animations + simultaneously, sequentially, or after a specified delay. You can also nest {@link + android.animation.AnimatorSet} objects within each other.</p> + + <p>The following sample code taken from the <a href= + "{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/BouncingBalls.html"> + Bouncing Balls</a> sample (modified for simplicity) plays the following + {@link android.animation.Animator} objects in the following manner:</p> + + <ol> + <li>Plays <code>bounceAnim</code>.</li> + + <li>Plays <code>squashAnim1</code>, <code>squashAnim2</code>, + <code>stretchAnim1</code>, and <code>stretchAnim2</code> at the same time.</li> + + <li>Plays <code>bounceBackAnim</code>.</li> + + <li>Plays <code>fadeAnim</code>.</li> + </ol> + <pre>AnimatorSet bouncer = new AnimatorSet(); +bouncer.play(bounceAnim).before(squashAnim1); +bouncer.play(squashAnim1).with(squashAnim2); +bouncer.play(squashAnim1).with(stretchAnim1); +bouncer.play(squashAnim1).with(stretchAnim2); +bouncer.play(bounceBackAnim).after(stretchAnim2); +ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); +fadeAnim.setDuration(250); +AnimatorSet animatorSet = new AnimatorSet(); +animatorSet.play(bouncer).before(fadeAnim); +animatorSet.start(); +</pre> + + <p>For a more complete example on how to use animator sets, see the <a href= + "{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/animation/BouncingBalls.html"> + Bouncing Balls</a> sample in APIDemos.</p> + + <h3 id="declaring-xml">Declaring animations in XML</h3> + + <p>As with <a href="#view-animation">view animation</a>, you can declare property animations with + XML instead of doing it programmatically. The following Android classes also have XML + declaration support with the following XML tags:</p> + + <ul> + <li>{@link android.animation.ValueAnimator} - <code><animator></code></li> + + <li>{@link android.animation.ObjectAnimator} - <code><objectAnimator></code></li> + + <li>{@link android.animation.AnimatorSet} - <code><AnimatorSet></code></li> + </ul> + + <p>Both <code><animator></code> ({@link android.animation.ValueAnimator}) and + <code><objectAnimator></code> ({@link android.animation.ObjectAnimator}) have the + following attributes:</p> + + <dl> + <dt><code>android:duration</code></dt> + <dd>The number of milliseconds that the animation runs.</dd> + + <dt><code>android:valueFrom</code> and <code>android:valueTo</code></dt> + <dd>The values being animated + between. These are restricted to numbers (<code>float</code> or <code>int</code>) in + XML. They can be <code>float</code>, <code>int</code>, or any kind of + <code>Object</code> when creating animations programmatically.</dd> + + <dt><code>android:valueType</code></dt> + <dd>Set to either <code>"floatType"</code> or <code>"intType"</code>.</dd> + + <dt><code>android:startDelay</code></dt> + <dd>The delay, in milliseconds, before the animation begins + playing (after calling {@link android.animation.ValueAnimator#start start()}).</dd> + + <dt><code>android:repeatCount</code></dt> + <dd>How many times to repeat an animation. Set to + <code>"-1"</code> for infinite repeating or to a positive integer. For example, a value of + <code>"1"</code> means that the animation is repeated once after the initial run of the + animation, so the animation plays a total of two times. The default value is + <code>"0"</code>.</dd> + + <dt><code>android:repeatMode</code></dt> + <dd>How an animation behaves when it reaches the end of the + animation. <code>android:repeatCount</code> must be set to a positive integer or + <code>"-1"</code> for this attribute to have an effect. Set to <code>"reverse"</code> to + have the animation reverse direction with each iteration or <code>"repeat"</code> to + have the animation loop from the beginning each time.</dd> + </dl> + + <p>The <code>objectAnimator</code> ({@link android.animation.ObjectAnimator}) element has the + additional attribute <code>propertyName</code>, that lets you specify the name of the + property being animated. The <code>objectAnimator</code> element does not expose a + <code>target</code> attribute, however, so you cannot set the object to animate in the + XML declaration. You have to inflate the XML resource by calling + {@link android.animation.AnimatorInflater#loadAnimator loadAnimator()} and call + {@link android.animation.ObjectAnimator#setTarget setTarget()} to set the target object, before calling + {@link android.animation.ObjectAnimator#start start()}.</p> + + <p>The <code>set</code> element ({@link android.animation.AnimatorSet}) exposes a single + attribute, <code>ordering</code>. Set this attribute to <code>together</code> (default) + to play all the animations in this set at once. Set this attribute to + <code>sequentially</code> to play the animations in the order they are declared.</p> + + <p>You can specify nested <code>set</code> tags to further group animations together. + The animations that you want to group together should be children of the + <code>set</code> tag and can define their own <code>ordering</code> attribute.</p> + + <p>As an example, this XML code creates an {@link android.animation.AnimatorSet} object + that animates x and y at the same time (<code>together</code> is the default ordering + when nothing is specified), then runs an animation that fades an object out:</p> + <pre><set android:ordering="sequentially"> + <set> + <objectAnimator + android:propertyName="x" + android:duration="500" + android:valueTo="400" + android:valueType="int"/> + <objectAnimator + android:propertyName="y" + android:duration="500" + android:valueTo="300" + android:valueType="int"/> + </set> + <objectAnimator + android:propertyName="alpha" + android:duration="500" + android:valueTo="0f"/> +</set></pre> + + <p>In order to run this animation, you must inflate the XML resources in your code to + an {@link android.animation.AnimatorSet} object, and then set the target objects for all of + the animations before starting the animation set. Calling {@link + android.animation.AnimatorSet#setTarget setTarget()} sets a single target object for + all children of the {@link android.animation.AnimatorSet}.</p> + + <h2 id="view-animation">View Animation</h2>You can use View Animation in any View + object to perform tweened animation and frame by frame animation. Tween animation + calculates the animation given information such as the start point, end point, size, + rotation, and other common aspects of an animation. Frame by frame animation lets you + load a series of Drawable resources one after another to create an animation. + + <h3 id="tween-animation">Tween Animation</h3> + + <p>A tween animation can perform a series of simple transformations (position, size, + rotation, and transparency) on the contents of a View object. So, if you have a + {@link android.widget.TextView} object, you can move, rotate, grow, or shrink the text. If it has a background + image, the background image will be transformed along with the text. The {@link + android.view.animation animation package} provides all the classes used in a tween + animation.</p> + + <p>A sequence of animation instructions defines the tween animation, defined by either + XML or Android code. As with defining a layout, an XML file is recommended because it's + more readable, reusable, and swappable than hard-coding the animation. In the example + below, we use XML. (To learn more about defining an animation in your application code, + instead of XML, refer to the {@link android.view.animation.AnimationSet} class and + other {@link android.view.animation.Animation} subclasses.)</p> + + <p>The animation instructions define the transformations that you want to occur, when + they will occur, and how long they should take to apply. Transformations can be + sequential or simultaneous — for example, you can have the contents of a TextView + move from left to right, and then rotate 180 degrees, or you can have the text move and + rotate simultaneously. Each transformation takes a set of parameters specific for that + transformation (starting size and ending size for size change, starting angle and + ending angle for rotation, and so on), and also a set of common parameters (for + instance, start time and duration). To make several transformations happen + simultaneously, give them the same start time; to make them sequential, calculate the + start time plus the duration of the preceding transformation.</p> + + <p>The animation XML file belongs in the <code>res/anim/</code> directory of your + Android project. The file must have a single root element: this will be either a single + <code><alpha></code>, <code><scale></code>, <code><translate></code>, + <code><rotate></code>, interpolator element, or <code><set></code> element + that holds groups of these elements (which may include another + <code><set></code>). By default, all animation instructions are applied + simultaneously. To make them occur sequentially, you must specify the + <code>startOffset</code> attribute, as shown in the example below.</p> + + <p>The following XML from one of the ApiDemos is used to stretch, then simultaneously + spin and rotate a View object.</p> + <pre><set android:shareInterpolator="false"> + <scale + android:interpolator="@android:anim/accelerate_decelerate_interpolator" + android:fromXScale="1.0" + android:toXScale="1.4" + android:fromYScale="1.0" + android:toYScale="0.6" + android:pivotX="50%" + android:pivotY="50%" + android:fillAfter="false" + android:duration="700" /> + <set android:interpolator="@android:anim/decelerate_interpolator"> + <scale + android:fromXScale="1.4" + android:toXScale="0.0" + android:fromYScale="0.6" + android:toYScale="0.0" + android:pivotX="50%" + android:pivotY="50%" + android:startOffset="700" + android:duration="400" + android:fillBefore="false" /> + <rotate + android:fromDegrees="0" + android:toDegrees="-45" + android:toYScale="0.0" + android:pivotX="50%" + android:pivotY="50%" + android:startOffset="700" + android:duration="400" /> + </set> +</set></pre> + + <p>Screen coordinates (not used in this example) are (0,0) at the upper left hand + corner, and increase as you go down and to the right.</p> + + <p>Some values, such as pivotX, can be specified relative to the object itself or + relative to the parent. Be sure to use the proper format for what you want ("50" for + 50% relative to the parent, or "50%" for 50% relative to itself).</p> + + <p>You can determine how a transformation is applied over time by assigning an {@link + android.view.animation.Interpolator}. Android includes several Interpolator subclasses + that specify various speed curves: for instance, {@link + android.view.animation.AccelerateInterpolator} tells a transformation to start slow and + speed up. Each one has an attribute value that can be applied in the XML.</p> + + <p>With this XML saved as <code>hyperspace_jump.xml</code> in the + <code>res/anim/</code> directory of the project, the following code will reference + it and apply it to an {@link android.widget.ImageView} object from the layout.</p> + <pre> +ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage); +Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); +spaceshipImage.startAnimation(hyperspaceJumpAnimation); +</pre> + + <p>As an alternative to <code>startAnimation()</code>, you can define a starting time + for the animation with <code>{@link android.view.animation.Animation#setStartTime(long) + Animation.setStartTime()}</code>, then assign the animation to the View with + <code>{@link android.view.View#setAnimation(android.view.animation.Animation) + View.setAnimation()}</code>.</p> + + <p>For more information on the XML syntax, available tags and attributes, see <a href= + "{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p> + + <p class="note"><strong>Note:</strong> Regardless of how your animation may move or + resize, the bounds of the View that holds your animation will not automatically adjust + to accommodate it. Even so, the animation will still be drawn beyond the bounds of its + View and will not be clipped. However, clipping <em>will occur</em> if the animation + exceeds the bounds of the parent View.</p> + + <h3 id="frame-animation">Frame Animation</h3> + + <p>This is a traditional animation in the sense that it is created with a sequence of + different images, played in order, like a roll of film. The {@link + android.graphics.drawable.AnimationDrawable} class is the basis for frame + animations.</p> + + <p>While you can define the frames of an animation in your code, using the {@link + android.graphics.drawable.AnimationDrawable} class API, it's more simply accomplished + with a single XML file that lists the frames that compose the animation. Like the tween + animation above, the XML file for this kind of animation belongs in the + <code>res/drawable/</code> directory of your Android project. In this case, the + instructions are the order and duration for each frame of the animation.</p> + + <p>The XML file consists of an <code><animation-list></code> element as the root + node and a series of child <code><item></code> nodes that each define a frame: a + drawable resource for the frame and the frame duration. Here's an example XML file for + a frame-by-frame animation:</p> + <pre> +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" + android:oneshot="true"> + <item android:drawable="@drawable/rocket_thrust1" android:duration="200" /> + <item android:drawable="@drawable/rocket_thrust2" android:duration="200" /> + <item android:drawable="@drawable/rocket_thrust3" android:duration="200" /> +</animation-list> +</pre> + + <p>This animation runs for just three frames. By setting the + <code>android:oneshot</code> attribute of the list to <var>true</var>, it will cycle + just once then stop and hold on the last frame. If it is set <var>false</var> then the + animation will loop. With this XML saved as <code>rocket_thrust.xml</code> in the + <code>res/drawable/</code> directory of the project, it can be added as the background + image to a View and then called to play. Here's an example Activity, in which the + animation is added to an {@link android.widget.ImageView} and then animated when the + screen is touched:</p> + <pre>AnimationDrawable rocketAnimation; + +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image); + rocketImage.setBackgroundResource(R.drawable.rocket_thrust); + rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); +} + +public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + rocketAnimation.start(); + return true; + } + return super.onTouchEvent(event); +}</pre> + + <p>It's important to note that the <code>start()</code> method called on the + AnimationDrawable cannot be called during the <code>onCreate()</code> method of your + Activity, because the AnimationDrawable is not yet fully attached to the window. If you + want to play the animation immediately, without requiring interaction, then you might + want to call it from the <code>{@link + android.app.Activity#onWindowFocusChanged(boolean) onWindowFocusChanged()}</code> + method in your Activity, which will get called when Android brings your window into + focus.</p> + + <p>For more information on the XML syntax, available tags and attributes, see <a href= + "{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p>
\ No newline at end of file diff --git a/docs/html/guide/topics/location/obtaining-user-location.jd b/docs/html/guide/topics/location/obtaining-user-location.jd index bc782d2..3b450f0 100644 --- a/docs/html/guide/topics/location/obtaining-user-location.jd +++ b/docs/html/guide/topics/location/obtaining-user-location.jd @@ -421,8 +421,8 @@ lat/long coordinates, with a GPX file for route playback, or a KML file for mult <li>Use a KML file describing individual place marks for sequenced playback to the device.</li> </ul> -<p>For more information on using DDMS to spoof location data, see the -<a href="{@docRoot}guide/developing/tools/ddms.html#emulator-control">Using DDMS guide</a>. +<p>For more information on using DDMS to spoof location data, see +<a href="{@docRoot}guide/developing/debugging/ddms.html">Using DDMS</a>. <h3 id="MockGeo">Using the "geo" command in the emulator console</h3> @@ -451,4 +451,4 @@ lat/long coordinates, with a GPX file for route playback, or a KML file for mult </ol> <p>For information about how to connect to the emulator console, see -<a href="{@docRoot}guide/developing/tools/emulator.html#console">Using the Emulator Console</a>.</p> +<a href="{@docRoot}guide/developing/devices/emulator.html#console">Using the Emulator Console</a>.</p> diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index e030a4c..2648cb7 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -290,7 +290,8 @@ activity is ignored. The activity is not re-parented, but destroyed. <dd>An icon representing the activity. The icon is displayed to users when a representation of the activity is required on-screen. For example, icons for activities that initiate tasks are displayed in the launcher window. -The icon is often accompanied by a label (see the {@code label} attribute). +The icon is often accompanied by a label (see the <a href="#label">{@code +android:label}</a> attribute). </p> <p> diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd index 9ac07fd..1fadc6e 100644 --- a/docs/html/guide/topics/manifest/application-element.jd +++ b/docs/html/guide/topics/manifest/application-element.jd @@ -12,6 +12,7 @@ page.title=<application> android:<a href="#icon">icon</a>="<i>drawable resource</i>" android:<a href="#killrst">killAfterRestore</a>=["true" | "false"] android:<a href="#label">label</a>="<i>string resource</i>" + android:<a href="#logo">logo</a>="<i>drawable resource</i>" android:<a href="#space">manageSpaceActivity</a>="<i>string</i>" android:<a href="#nm">name</a>="<i>string</i>" android:<a href="#prmsn">permission</a>="<i>string</i>" @@ -121,7 +122,7 @@ each of the application's components. See the individual <p> This attribute must be set as a reference to a drawable resource containing -the image definition. There is no default icon. +the image (for example {@code "@drawable/icon"}). There is no default icon. </p></dd> <dt><a name="killrst"></a>{@code android:killAfterRestore}</dt> @@ -154,6 +155,11 @@ However, as a convenience while you're developing the application, it can also be set as a raw string. </p></dd> +<dt><a name="logo"></a>{@code android:logo}</dt> +<dd>A logo for the application as whole, and the default logo for activities. +<p>This attribute must be set as a reference to a drawable resource containing +the image (for example {@code "@drawable/logo"}). There is no default logo.</p></dd> + <dt><a name="space"></a>{@code android:manageSpaceActivity}</dt> <dd>The fully qualified name of an Activity subclass that the system can launch to let users manage the memory occupied by the application diff --git a/docs/html/guide/topics/media/index.jd b/docs/html/guide/topics/media/index.jd index 8e18754..e355212 100644 --- a/docs/html/guide/topics/media/index.jd +++ b/docs/html/guide/topics/media/index.jd @@ -115,9 +115,8 @@ Resume playback from where you paused with <p>{@link android.media.MediaPlayer#stop() stop()} and {@link android.media.MediaPlayer#pause() pause()} work the same as discussed above.</p> - <p class="note"><strong>Note:</strong> It is possible that <code>mp</code> could be - null, so good code should <code>null</code> check after the <code>new</code>. - Also, <code>IllegalArgumentException</code> and <code>IOException</code> either + <p class="note"><strong>Note:</strong> + <code>IllegalArgumentException</code> and <code>IOException</code> either need to be caught or passed on when using <code>setDataSource()</code>, since the file you are referencing may not exist.</p> <p class="note"><strong>Note:</strong> diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd index d9f619f..cee8fc3 100644 --- a/docs/html/guide/topics/resources/drawable-resource.jd +++ b/docs/html/guide/topics/resources/drawable-resource.jd @@ -74,7 +74,7 @@ android:drawable="@color/green"}).</p> alias resource ID in XML.</p> <p class="note"><strong>Note:</strong> Bitmap files may be automatically optimized with lossless -image compression by the <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For +image compression by the <code>aapt</code> tool during the build process. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd index cde72bd..33c782b 100644 --- a/docs/html/guide/topics/resources/menu-resource.jd +++ b/docs/html/guide/topics/resources/menu-resource.jd @@ -36,22 +36,26 @@ In XML: <code>@[<em>package</em>:]menu.<em>filename</em></code> <?xml version="1.0" encoding="utf-8"?> <<a href="#menu-element">menu</a> xmlns:android="http://schemas.android.com/apk/res/android"> <<a href="#item-element">item</a> android:id="@[+][<em>package</em>:]id/<em>resource_name</em>" - android:menuCategory=["container" | "system" | "secondary" | "alternative"] - android:orderInCategory="<em>integer</em>" android:title="<em>string</em>" android:titleCondensed="<em>string</em>" android:icon="@[package:]drawable/<em>drawable_resource_name</em>" + android:onClick="<em>method name</em>" + android:showAsAction=["ifRoom" | "never" | "withText" | "always"] + android:actionLayout="@[package:]layout/<em>layout_resource_name</em>" + android:actionViewClass="<em>class name</em>" android:alphabeticShortcut="<em>string</em>" android:numericShortcut="<em>string</em>" android:checkable=["true" | "false"] android:visible=["visible" | "invisible" | "gone"] - android:enabled=["enabled" | "disabled"] /> + android:enabled=["enabled" | "disabled"] + android:menuCategory=["container" | "system" | "secondary" | "alternative"] + android:orderInCategory="<em>integer</em>" /> <<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>" - android:menuCategory=["container" | "system" | "secondary" | "alternative"] - android:orderInCategory="<em>integer</em>" android:checkableBehavior=["none" | "all" | "single"] android:visible=["visible" | "invisible" | "gone"] - android:enabled=["enabled" | "disabled"] > + android:enabled=["enabled" | "disabled"] + android:menuCategory=["container" | "system" | "secondary" | "alternative"] + android:orderInCategory="<em>integer</em>" > <<a href="#item-element">item</a> /> </group> <<a href="#item-element">item</a> > @@ -73,95 +77,155 @@ In XML: <code>@[<em>package</em>:]menu.<em>filename</em></code> <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>xmlns:android</code></dt> - <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be - <code>"http://schemas.android.com/apk/res/android"</code>. + <dd><em>XML namespace</em>. <strong>Required.</strong> Defines the XML namespace, which +must be <code>"http://schemas.android.com/apk/res/android"</code>. </dl> </dd> - <dt id="group-element"><code><group></code></dt> - <dd>A menu group (to create a collection of items that share traits, such as whether they are -visible, enabled, or checkable). Contains one or more <code><item></code> elements. Must be a -child of a <code><menu></code> element. + + <dt id="item-element"><code><item></code></dt> + <dd>A menu item. May contain a <code><menu></code> element (for a Sub + Menu). Must be a child of a <code><menu></code> or <code><group></code> element. <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>android:id</code></dt> <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form: -<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd> +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new +ID.</dd> + <dt><code>android:title</code></dt> + <dd><em>String resource</em>. The menu title as a string resource or raw string.</dd> + <dt><code>android:titleCondensed</code></dt> + <dd><em>String resource</em>. A condensed title as a string resource or a raw string. This +title is used for situations in which the normal title is too long.</dd> + + <dt><code>android:icon</code></dt> + <dd><em>Drawable resource</em>. An image to be used as the menu item icon.</dd> + + <dt><code>android:onClick</code></dt> + <dd><em>Method name</em>. The method to call when this menu item is clicked. The +method must be declared in the activity as public and accept a {@link android.view.MenuItem} as its +only parameter, which indicates the item clicked. This method takes precedence over the standard +callback to {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}. See the +example at the bottom. + <p class="warning"><strong>Warning:</strong> If you obfuscate your code using <a +href="{@docRoot}guide/developing/tools/proguard.html">ProGuard</a> (or a similar tool), +be sure to exclude the method you specify in this attribute from renaming, because it can break the +functionality.</p> + <p>Introduced in API Level HONEYCOMB.</p></dd> + + <dt><code>android:showAsAction</code></dt> + <dd><em>Keyword</em>. When and how this item should appear as an action item in the Action +Bar. A menu item can appear as an action item only when the activity includes an {@link +android.app.ActionBar} (introduced in API Level HONEYCOMB). Valid values: + <table> + <tr><th>Value</th><th>Description</th></tr> + <tr><td><code>ifRoom</code></td><td>Only place this item in the Action Bar if +there is room for it.</td></tr> + <tr><td><code>withText</code></td><td>Also include the title text (defined +by {@code android:title}) with the action item. You can include this value along with one +of the others as a flag set, by separating them with a pipe {@code |}.</td></tr> + <tr><td><code>never</code></td><td>Never place this item in the Action Bar.</td></tr> + <tr><td><code>always</code></td><td>Always place this item in the Action Bar. +Avoid using this unless it's critical that the item always appear in the action +bar. Setting multiple items to always appear as action items can result in them overlapping +with other UI in the action bar.</td></tr> + </table> + <p>See <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a> for +more information.</p> + <p>Introduced in API Level HONEYCOMB.</p> + </dd> + + <dt><code>android:actionViewLayout</code></dt> + <dd><em>Layout resource</em>. A layout to use as the action view. + <p>See <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a> for +more information.</p> + <p>Introduced in API Level HONEYCOMB.</p></dd> + + <dt><code>android:actionViewClassName</code></dt> + <dd><em>Class name</em>. A fully-qualified class name for the {@link android.view.View} +to use as the action view. + <p>See <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a> for +more information.</p> + <p class="warning"><strong>Warning:</strong> If you obfuscate your code using <a +href="{@docRoot}guide/developing/tools/proguard.html">ProGuard</a> (or a similar tool), +be sure to exclude the class you specify in this attribute from renaming, because it can break the +functionality.</p> + <p>Introduced in API Level HONEYCOMB.</p></dd> + + + <dt><code>android:alphabeticShortcut</code></dt> + <dd><em>Char</em>. A character for the alphabetic shortcut key.</dd> + <dt><code>android:numericShortcut</code></dt> + <dd><em>Integer</em>. A number for the numeric shortcut key.</dd> + <dt><code>android:checkable</code></dt> + <dd><em>Boolean</em>. "true" if the item is checkable.</dd> + <dt><code>android:checked</code></dt> + <dd><em>Boolean</em>. "true" if the item is checked by default.</dd> + <dt><code>android:visible</code></dt> + <dd><em>Boolean</em>. "true" if the item is visible by default.</dd> + <dt><code>android:enabled</code></dt> + <dd><em>Boolean</em>. "true" if the item is enabled by default.</dd> <dt><code>android:menuCategory</code></dt> <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*} - constants, which define the group's priority. Valid values: + constants, which define the item's priority. Valid values: <table> <tr><th>Value</th><th>Description</th></tr> - <tr><td><code>container</code></td><td>For groups that are part of a + <tr><td><code>container</code></td><td>For items that are part of a container.</td></tr> - <tr><td><code>system</code></td><td>For groups that are provided by the + <tr><td><code>system</code></td><td>For items that are provided by the system.</td></tr> - <tr><td><code>secondary</code></td><td>For groups that are user-supplied secondary + <tr><td><code>secondary</code></td><td>For items that are user-supplied secondary (infrequently used) options.</td></tr> - <tr><td><code>alternative</code></td><td>For groups that are alternative actions + <tr><td><code>alternative</code></td><td>For items that are alternative actions on the data that is currently displayed.</td></tr> </table> </dd> <dt><code>android:orderInCategory</code></dt> - <dd><em>Integer</em>. The default order of the items within the category.</dd> + <dd><em>Integer</em>. The order of "importance" of the item, within a group.</dd> + </dl> + </dd> + + <dt id="group-element"><code><group></code></dt> + <dd>A menu group (to create a collection of items that share traits, such as whether they are +visible, enabled, or checkable). Contains one or more <code><item></code> elements. Must be a +child of a <code><menu></code> element. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:id</code></dt> + <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, +use the form: +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new +ID.</dd> <dt><code>android:checkableBehavior</code></dt> <dd><em>Keyword</em>. The type of checkable behavior for the group. Valid values: <table> <tr><th>Value</th><th>Description</th></tr> <tr><td><code>none</code></td><td>Not checkable</td></tr> <tr><td><code>all</code></td><td>All items can be checked (use checkboxes)</td></tr> - <tr><td><code>single</code></td><td>Only one item can be checked (use radio buttons)</td></tr> + <tr><td><code>single</code></td><td>Only one item can be checked (use radio +buttons)</td></tr> </table> </dd> <dt><code>android:visible</code></dt> <dd><em>Boolean</em>. "true" if the group is visible.</dd> <dt><code>android:enabled</code></dt> <dd><em>Boolean</em>. "true" if the group is enabled.</dd> - </dl> - </dd> - <dt id="item-element"><code><item></code></dt> - <dd>A menu item. May contain a <code><menu></code> element (for a Sub - Menu). Must be a child of a <code><menu></code> or <code><group></code> element. - <p class="caps">attributes:</p> - <dl class="atn-list"> - <dt><code>android:id</code></dt> - <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form: -<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd> <dt><code>android:menuCategory</code></dt> <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*} - constants, which define the item's priority. Valid values: + constants, which define the group's priority. Valid values: <table> <tr><th>Value</th><th>Description</th></tr> - <tr><td><code>container</code></td><td>For items that are part of a + <tr><td><code>container</code></td><td>For groups that are part of a container.</td></tr> - <tr><td><code>system</code></td><td>For items that are provided by the + <tr><td><code>system</code></td><td>For groups that are provided by the system.</td></tr> - <tr><td><code>secondary</code></td><td>For items that are user-supplied secondary + <tr><td><code>secondary</code></td><td>For groups that are user-supplied secondary (infrequently used) options.</td></tr> - <tr><td><code>alternative</code></td><td>For items that are alternative actions + <tr><td><code>alternative</code></td><td>For groups that are alternative actions on the data that is currently displayed.</td></tr> </table> </dd> <dt><code>android:orderInCategory</code></dt> - <dd><em>Integer</em>. The order of "importance" of the item, within a group.</dd> - <dt><code>android:title</code></dt> - <dd><em>String</em>. The menu title.</dd> - <dt><code>android:titleCondensed</code></dt> - <dd><em>String</em>. A condensed title, for situations in which the normal title is -too long.</dd> - <dt><code>android:icon</code></dt> - <dd><em>Drawable resource</em>. An image to be used as the menu item icon.</dd> - <dt><code>android:alphabeticShortcut</code></dt> - <dd><em>Char</em>. A character for the alphabetic shortcut key.</dd> - <dt><code>android:numericShortcut</code></dt> - <dd><em>Integer</em>. A number for the numeric shortcut key.</dd> - <dt><code>android:checkable</code></dt> - <dd><em>Boolean</em>. "true" if the item is checkable.</dd> - <dt><code>android:checked</code></dt> - <dd><em>Boolean</em>. "true" if the item is checked by default.</dd> - <dt><code>android:visible</code></dt> - <dd><em>Boolean</em>. "true" if the item is visible by default.</dd> - <dt><code>android:enabled</code></dt> - <dd><em>Boolean</em>. "true" if the item is enabled by default.</dd> + <dd><em>Integer</em>. The default order of the items within the category.</dd> </dl> </dd> </dl> @@ -174,17 +238,21 @@ too long.</dd> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/item1" android:title="@string/item1" - android:icon="@drawable/group_item1_icon" /> + android:icon="@drawable/group_item1_icon" + android:showAsAction="ifRoom|withText"/> <group android:id="@+id/group"> <item android:id="@+id/group_item1" + android:onClick="onGroupItemClick" android:title="@string/group_item1" android:icon="@drawable/group_item1_icon" /> <item android:id="@+id/group_item2" + android:onClick="onGroupItemClick" android:title="G@string/group_item2" android:icon="@drawable/group_item2_icon" /> </group> <item android:id="@+id/submenu" - android:title="@string/submenu_title" > + android:title="@string/submenu_title" + android:showAsAction="ifRoom|withText" > <menu> <item android:id="@+id/submenu_item1" android:title="@string/submenu_item1" /> @@ -192,15 +260,24 @@ too long.</dd> </item> </menu> </pre> - <p>This application code will inflate the menu from the {@link -android.app.Activity#onCreateOptionsMenu(Menu)} callback:</p> + <p>The following application code inflates the menu from the {@link +android.app.Activity#onCreateOptionsMenu(Menu)} callback and also declares the on-click +callback for two of the items:</p> <pre> public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.example_menu, menu); - return true; + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.example_menu, menu); + return true; +} + +public void onGroupItemClick(MenuItem item) { + // One of the group items (using the onClick attribute) was clicked + // The item parameter passed here indicates which item it is + // All other menu item clicks are handled by {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} } </pre> +<p class="note"><strong>Note:</strong> The {@code android:showAsAction} attribute is +available only on Android X.X (API Level HONEYCOMB) and greater.</p> </dd> <!-- end example --> diff --git a/docs/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd index 81c5d55..2db38f1 100644 --- a/docs/html/guide/topics/resources/string-resource.jd +++ b/docs/html/guide/topics/resources/string-resource.jd @@ -12,8 +12,8 @@ your application with strings:</p> <dd>XML resource that provides a single string.</dd> <dt><a href="#StringArray">String Array</a></dt> <dd>XML resource that provides an array of strings.</dd> - <dt><a href="#Plurals">Plurals</a></dt> - <dd>XML resource that carries different strings for different pluralizations + <dt><a href="#Plurals">Quantity Strings (Plurals)</a></dt> + <dd>XML resource that carries different strings for different quantities of the same word or phrase.</dd> </dl> @@ -218,13 +218,30 @@ getStringArray}(R.array.planets_array); -<h2 id="Plurals">Plurals</h2> +<h2 id="Plurals">Quantity Strings (Plurals)</h2> -<p>A pair of strings that each provide a different plural form of the same word or phrase, -which you can collectively reference from the application. When you request the plurals -resource using a method such as {@link android.content.res.Resources#getQuantityString(int,int) -getQuantityString()}, you must pass a "count", which will determine the plural form you -require and return that string to you.</p> +<p>Different languages have different rules for grammatical agreement with quantity. In English, +for example, the quantity 1 is a special case. We write "1 book", but for any other quantity we'd +write "<i>n</i> books". This distinction between singular and plural is very common, but other +languages make finer distinctions. The full set supported by Android is <code>zero</code>, +<code>one</code>, <code>two</code>, <code>few</code>, <code>many</code>, and <code>other</code>. + +<p>The rules for deciding which case to use for a given language and quantity can be very complex, +so Android provides you with methods such as +{@link android.content.res.Resources#getQuantityString(int,int) getQuantityString()} to select +the appropriate resource for you. + +<p>Note that the selection is made based on grammatical necessity. A string for <code>zero</code> +in English will be ignored even if the quantity is 0, because 0 isn't grammatically different +from 2, or any other number except 1 ("zero books", "one book", "two books", et cetera). +Don't be misled either by the fact that, say, <code>two</code> sounds like it could only apply to +the quantity 2: a language may require that 2, 12, 102 (et cetera) are all treated like one +another but differently to other quantities. Rely on your translator to know what distinctions +their language actually insists upon. + +<p>It's often possible to avoid quantity strings by using quantity-neutral formulations such as +"Books: 1". This will make your life and your translators' lives easier, if it's a style that's +in keeping with your application. <p class="note"><strong>Note:</strong> A plurals collection is a simple resource that is referenced using the value provided in the {@code name} attribute (not the name of the XML @@ -251,7 +268,7 @@ In Java: <code>R.plurals.<em>plural_name</em></code> <<a href="#plurals-element">plurals</a> name="<em>plural_name</em>"> <<a href="#plurals-item-element">item</a> - quantity=["one" | "other"] + quantity=["zero" | "one" | "two" | "few" | "many" | "other"] ><em>text_string</em></item> </plurals> </resources> @@ -285,16 +302,27 @@ Styling</a>, below, for information about to properly style and format your stri <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>quantity</code></dt> - <dd><em>Keyword</em>. A value indicating the case in which this string should be used. Valid -values: + <dd><em>Keyword</em>. A value indicating when this string should be used. Valid +values, with non-exhaustive examples in parentheses: <table> <tr><th>Value</th><th>Description</th></tr> <tr> - <td>{@code one}</td><td>When there is one (a singular string).</td> + <td>{@code zero}</td><td>When the language requires special treatment of the number 0 (as in Arabic).</td> + </tr> + <tr> + <td>{@code one}</td><td>When the language requires special treatment of numbers like one (as with the number 1 in English and most other languages; in Russian, any number ending in 1 but not ending in 11 is in this class).</td> + </tr> + <tr> + <td>{@code two}</td><td>When the language requires special treatment of numbers like two (as in Welsh).</td> + </tr> + <tr> + <td>{@code few}</td><td>When the language requires special treatment of "small" numbers (as with 2, 3, and 4 in Czech; or numbers ending 2, 3, or 4 but not 12, 13, or 14 in Polish).</td> </tr> <tr> - <td>{@code other}</td><td>When the quantity is anything other than one (a plural -string, but also used when the count is zero).</td> + <td>{@code many}</td><td>When the language requires special treatment of "large" numbers (as with numbers ending 11-99 in Maltese).</td> + </tr> + <tr> + <td>{@code other}</td><td>When the language does not require special treatment of the given quantity.</td> </tr> </table> </dd> @@ -315,6 +343,17 @@ string, but also used when the count is zero).</td> </plurals> </resources> </pre> + <p>XML file saved at {@code res/values-pl/strings.xml}:</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <plurals name="numberOfSongsAvailable"> + <item quantity="one">Znaleziono jedną piosenkę.</item> + <item quantity="few">Znaleziono %d piosenki.</item> + <item quantity="other">Znaleziono %d piosenek.</item> + </plurals> +</resources> +</pre> <p>Java code:</p> <pre> int count = getNumberOfsongsAvailable(); diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd index d4b0dcc..6f3048c 100755 --- a/docs/html/guide/topics/testing/testing_android.jd +++ b/docs/html/guide/topics/testing/testing_android.jd @@ -625,9 +625,8 @@ The <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerci </p> <p> When possible, you should run these tests on an actual device. If this is not possible, you can - use the <a href="{@docRoot}guide/developing/tools/emulator.html">Android Emulator</a> with - <a href="{@docRoot}guide/developing/tools/avd.html">Android Virtual Devices</a> configured for - the hardware, screens, and versions you want to test. + use the <a href="{@docRoot}guide/developing/devices/emulator.html">Android Emulator</a> with + Android Virtual Devices configured for the hardware, screens, and versions you want to test. </p> <h2 id="NextSteps">Next Steps</h2> <p> diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd new file mode 100644 index 0000000..376bf6a --- /dev/null +++ b/docs/html/guide/topics/ui/actionbar.jd @@ -0,0 +1,593 @@ +page.title=Using the Action Bar +parent.title=User Interface +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>Quickview</h2> + <ul> + <li>A replacement for the title bar that includes the application icon and activity title</li> + <li>Provides action items from the Options Menu and modes of navigating around the +application</li> + <li>Supports custom views, including an embedded search box</li> + <li>Requires API Level HONEYCOMB</li> + </ul> + + <h2>In this document</h2> + <ol> + <li><a href="#Adding">Adding the Action Bar</a></li> + <li><a href="#ActionItems">Adding Action Items</a> + <ol> + <li><a href="#Home">Using the application icon as an action item</a></li> + </ol> + </li> + <li><a href="#ActionView">Adding an Action View</a></li> + <li><a href="#Tabs">Adding Tabs</a></li> + <li><a href="#Dropdown">Adding Drop-down Navigation</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.ActionBar}</li> + <li>{@link android.view.Menu}</li> + </ol> + + <h2>See also</h2> + <ol> + <li><a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a></li> + </ol> +</div> +</div> + +<p>The Action Bar is a widget for activities that replaces the traditional title bar at +the top of an activity. By default, the Action Bar includes the application logo on the left side, +followed by the activity title. The Action Bar offers several useful features for +applications—especially those targeted to tablet devices. The Action Bar features include +the ability to:</p> + +<ul> + <li>Display items from the <a +href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">Options Menu</a> as "action +items"—providing instant access to key user actions. (Menu items not appearing as action +items are placed in the Overflow Menu, revealed by a drop-down in the Action Bar.)</li> + <li>Provide tabs for navigating between <a +href="{@docRoot}guide/topics/fundamentals/fragments.html">fragments</a>.</li> + <li>Provide drop-down navigation items.</li> + <li>Provide interactive "action views" in place of action items.</li> + <li>Use the application logo as a "return home" or "up" navigation action.</li> +</ul> + +<img src="{@docRoot}images/ui/actionbar.png" height="36" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> A screenshot of the Action Bar in the NotePad +sample application, containing action items to save and delete the note.</p> + + +<h2 id="Adding">Adding the Action Bar</h2> + +<p>To add the Action Bar to your activities, simply target your application for HONEYCOMB or later, +using the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code +<uses-sdk>}</a> element. That is, by setting either the {@code android:minSdkVersion} or +{@code android:targetSdkVersion} to HONEYCOMB or later, each activity in your application will +include the Action Bar when running on devices with HONEYCOMB or later. For example:</p> + +<pre> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.helloworld" + android:versionCode="1" + android:versionName="1.0"> + <b><uses-sdk android:minSdkVersion="Froyo" /></b> + <application ... > + ... + </application> +</manifest> +</pre> + +<p>This also enables the "Holographic" theme for all your activities, which is the new default +application theme for HONEYCOMB and later.</p> + +<p class="note"><strong>Note:</strong> In order for the Holographic theme to be applied based on +the target platform version, the <a +href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code <uses-sdk>}</a> +element must appear <em>before</em> the <a +href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> +element.</p> + +<h3>Hide the Action Bar</h3> + +<p>If you want to hide the Action Bar for a particular activity, set the activity theme to +{@code android:style/Theme.NoTitleBar}. For example:</p> + +<pre> +<activity android:theme="@android:style/Theme.NoTitleBar"> +</pre> + + +<h2 id="ActionItems">Adding Action Items</h2> + +<p>For each action item you want to add to the Action Bar, you must add a menu item to the +activity's <a href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">Options Menu</a> and declare +that the item be shown as an action.</p> + +<div class="figure" style="width:359px"> + <img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" /> + <p class="img-caption"><strong>Figure 2.</strong> A screenshot from an Action Bar with two +action items.</p> +</div> + +<p>You can specify a menu item to appear as an action item—if there is room +for it—from the <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu +resource</a> by declaring {@code +android:showAsAction="ifRoom"} for the {@code <item>} element. This way, the item will display +in the Action Bar for quick access only if there is room available for it—if there's not +enough room, the item is placed the Overflow Menu (revealed by the menu icon on the right side +of the Action Bar). From your application code, you can specify the item to appear as an action item +by calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()} on the {@link +android.view.MenuItem} and passing {@link android.view.MenuItem#SHOW_AS_ACTION_IF_ROOM}.</p> + +<p>If your item supplies both a title and an icon, then the action item shows only +the icon by defult. If you want to include the text with the action item, add the <em>with text</em> +flag—in XML, add {@code withText} to the {@code android:showAsAction} attribute or, in +your application code, use the {@link android.view.MenuItem#SHOW_AS_ACTION_WITH_TEXT} flag when +calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()}. Figure 2 shows a screenshot +of an Action Bar with two action items that include text.</p> + +<p>Here's an example of how you can declare a menu item as an action item in a <a +href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> file:</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_add" + android:icon="@drawable/ic_menu_save" + android:title="@string/menu_save" + <b>android:showAsAction="ifRoom|withText"</b> /> +</menu> +</pre> + +<p>In this case, both the {@code ifRoom} and {@code withText} flags are set, so that when this +item appears as an action item, it includes the title text along with the icon.</p> + +<p>A menu item placed in the Action Bar triggers the same callback methods as other items in the +Options Menu. When the user selects an item in the Action Bar, your activity receives a call to +{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}, passing the +item ID. (If you added the item from a fragment, then the respective {@link +android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method is called +for that fragment.)</p> + +<p class="note"><strong>Note:</strong> Menu items that appear in the Overflow Menu (not as action +items) also show an icon, so it's best if you provide an icon for every menu item.</p> + +<p>You can also declare an item to <em>always</em> appear as an action item, but you should avoid +doing so. Most of the time, there will be enough room for several action items and they will appear +in the order you declare them. If you set items to always appear as action +items (instead of <em>if room</em>), then they are added without discrimination and there is a risk +that they will collide with other elements in the Action Bar, such as tabs or custom views.</p> + +<p>For more information about menus, see the <a +href="{@docRoot}guide/topics/ui/menus.html#options-menu">Creating Menus</a> developer guide.</p> + + +<h3 id="Home">Using the application icon as an action item</h3> + +<p>By default, the application icon appears in the Action Bar on the left side, but does nothing +when tapped. To use the application icon as an action item when tapped, you simply need to add a +condition to your {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method +that performs an action when the {@link android.view.MenuItem} ID is {@code android.R.id.home}. +This ID is delivered every time the user taps the application icon.</p> + +<p>For example, here's an implementation of {@link android.app.Activity#onOptionsItemSelected +onOptionsItemSelected()} that returns to the application's "home" activity:</p> + +<pre> +@Override +public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // app icon in Action Bar clicked; go home + Intent intent = new Intent(this, HomeActivity.class); + startActivity(intent); + break; + } + return super.onOptionsItemSelected(item); +} +</pre> + +<div class="figure" style="width:144px"> + <img src="{@docRoot}images/ui/actionbar-logo.png" height="140" alt="" /> + <p class="img-caption"><strong>Figure 3.</strong> The standard icon for the Email application +(top) and the "up navigation" icon (bottom).</p> +</div> + +<p>You can also use the application icon to provide "up" navigation. The way you handle the event +when a user taps the icon is the same, but if the user experience for the event is to <em>navigate +up to the parent activity</em>, then you should indicate this behavior by setting the +Action Bar to "show home as up." You can do so by calling {@link +android.app.ActionBar#setDisplayOptions setDisplayOptions()} on your activity's {@link +android.app.ActionBar}, and passing the {@link +android.app.ActionBar#DISPLAY_HOME_AS_UP} display option.</p> + +<p>To get the {@link android.app.ActionBar}, call {@link android.app.Activity#getActionBar} from +your {@link android.app.Activity} during {@link android.app.Activity#onCreate onCreate()} (but be +sure you do so <em>after</em> you've called {@link android.app.Activity#setContentView +setContentView()}).</p> + +<p>For example, here's how you can change the Action Bar display mode to show the application +icon as an "up" action:</p> + +<pre> +@Override +protected void onStart() { + super.onStart(); + ActionBar actionBar = this.getActionBar(); + actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP); +} +</pre> + +<p class="caution"><strong>Caution:</strong> If your activity does not have an Action Bar (if you +did not set the theme of your activity or application to the holographic or Action Bar theme), then +{@link android.app.Activity#getActionBar} returns null.</p> + + + +<h2 id="ActionView">Adding an Action View</h2> + +<div class="figure" style="width:281px"> + <img src="{@docRoot}images/ui/actionbar-actionview.png" alt="" /> + <p class="img-caption"><strong>Figure 4.</strong> An action view with a search widget.</p> +</div> + +<p>An action view is a customized view you can specify for an item in your Options Menu, to +display in the Action Bar when the item is included as an action item. For example, you can +include a menu item for "Search", which appears and behaves as a normal menu item in the Overflow +Menu, but, when set as an action item, it provides an action view that is a {@link +android.widget.SearchView}, so the user can initiate a search directly from the Action Bar. +Figure 4 shows an example of this, in which a menu item for search provides an action view +using the {@link android.widget.SearchView} widget.</p> + +<p>The best way to declare an action view for an item is in your <a +href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, using the {@code +android:actionLayout} or {@code android:actionViewClass} attribute.</p> + +<ul> + <li>The value for {@code android:actionLayout} must be a resource pointer to a layout file. +For example: +<pre> +<item android:id="@+id/menu_search" + android:title="Search" + android:icon="@drawable/ic_menu_search" + android:showAsAction="ifRoom" + <b>android:actionLayout="@layout/searchview"</b> /> +</pre></li> + <li>The value for {@code android:actionViewClass} must be a fully-qualified class name for +the {@link android.view.View} you want to use. For example: +<pre> +<item android:id="@+id/menu_search" + android:title="Search" + android:icon="@drawable/ic_menu_search" + android:showAsAction="ifRoom" + <b>android:actionViewClass="android.widget.SearchView"</b> /> +</pre></li> +</ul> + +<p>Now, when the menu item is displayed as an action item, it's action view appears instead of +the item's traditional icon and/or text. Yet, if for some reason the item does not appear in the +Action Bar, then it behaves like a normal menu item in the Overflow Menu and you must respond +accordingly when the user taps it, from the {@link android.app.Activity#onOptionsItemSelected +onOptionsItemSelected()} callback.</p> + +<p>When the activity first starts, the system populates the Action Bar and Overflow Menu by calling +{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}. +After you've inflated your menu in this method, you can acquire elements in an action view +(perhaps in order to attach listeners) by calling {@link android.view.Menu#findItem +findItem()} with the ID of the menu item, then {@link android.view.MenuItem#getActionView} on +the returned {@link android.view.MenuItem}. For example, the search widget from the above samples is +acquired like this:</p> + +<pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.options, menu); + SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); + // Set appropriate listeners for searchView + ... + return super.onCreateOptionsMenu(menu); +} +</pre> + +<p>For more information about enabling search in the Action Bar, see the <a +href="{@docRoot}guide/topics/search/index.html">Search</a> developer guide.</p> + + + +<h2 id="Tabs">Adding Tabs</h2> + +<p>The Action Bar can display tabs that allow the user navigate between different fragments in the +activity. Each tab can include a title and/or an icon.</p> + +<!-- +<div class="figure" style="width:300px"> + <img src="{@docRoot}images/ui/actionbar-tabs.png" alt="" /> + <p class="img-caption"><strong>Figure 5.</strong> Screenshot of tabs in the +Action Bar.</p> +</div> +--> + +<p>To begin, your layout must include a {@link android.view.View} in which each {@link +android.app.Fragment} associated with a tab is displayed. Be sure the view has an ID that you +can use to reference it from your code.</p> + +<p>To add tabs to the Action Bar:</p> +<ol> + <li>Create an implementation of {@link android.app.ActionBar.TabListener} to handle the +interaction events on the Action Bar tabs. You must implement all methods: {@link +android.app.ActionBar.TabListener#onTabSelected onTabSelected()}, {@link +android.app.ActionBar.TabListener#onTabUnselected onTabUnselected()}, and {@link +android.app.ActionBar.TabListener#onTabReselected onTabReselected()}. + <p>Each callback method passes the {@link android.app.ActionBar.Tab} that received the +event and a {@link android.app.FragmentTransaction} for you to perform the fragment +transactions (add or remove fragments).</p> + <p>For example:</p> +<pre> +private class MyTabListener implements ActionBar.TabListener { + private TabContentFragment mFragment; + + // Called to create an instance of the listener when adding a new tab + public TabListener(TabContentFragment fragment) { + mFragment = fragment; + } + + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) { + ft.add(R.id.fragment_content, mFragment, null); + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + ft.remove(mFragment); + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + // do nothing + } + +} +</pre> + <p>This implementation of {@link android.app.ActionBar.TabListener} adds a constructor +that saves the {@link android.app.Fragment} associated with a tab so that each callback +can add or remove that fragment.</p> + </li> + <li>Get the {@link android.app.ActionBar} for your activity by calling {@link +android.app.Activity#getActionBar} from your {@link android.app.Activity}, during {@link +android.app.Activity#onCreate onCreate()} (but be sure you do so <em>after</em> you've called +{@link android.app.Activity#setContentView setContentView()}).</li> + <li>Call {@link android.app.ActionBar#setNavigationMode(int) +setNavigationMode(NAVIGATION_MODE_TABS)} to enable tab mode for the {@link +android.app.ActionBar}.</li> + <li>Create each tab for the Action Bar: + <ol> + <li>Create a new {@link android.app.ActionBar.Tab} by calling {@link +android.app.ActionBar#newTab()} on the {@link android.app.ActionBar}.</li> + <li>Add title text and/or an icon for the tab by calling {@link +android.app.ActionBar.Tab#setText setText()} and/or {@link android.app.ActionBar.Tab#setIcon +setIcon()}. + <p class="note"><strong>Tip:</strong> These methods return the same {@link +android.app.ActionBar.Tab} instance, so you can chain the calls together.</p></li> + <li>Declare the {@link android.app.ActionBar.TabListener} to use for the tab by passing an +instance of your implementation to {@link android.app.ActionBar.Tab#setTabListener +setTabListener()}. + </ol> + </li> + <li>Add each {@link android.app.ActionBar.Tab} to the Action Bar by calling {@link +android.app.ActionBar#addTab addTab()} on the {@link android.app.ActionBar} and passing the +{@link android.app.ActionBar.Tab}.<> +</ol> +<p>For example, the following code combines steps 2 - 5 to create two tabs and add them to +the Action Bar:</p> +<pre> +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // setup Action Bar for tabs + final ActionBar actionBar = getActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + // remove the activity title to make space for tabs + actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); + + // instantiate fragment for the tab + Fragment artistsFragment = new ArtistsFragment(); + // add a new tab and set its title text and tab listener + actionBar.addTab(actionBar.newTab().setText(R.string.tab_artists) + .setTabListener(new TabListener(artistsFragment))); + + Fragment albumsFragment = new AlbumsFragment(); + actionBar.addTab(actionBar.newTab().setText(R.string.tab_albums) + .setTabListener(new TabListener(albumsFragment))); +} +</pre> + +<p>All the behaviors that occur when a tab is selected must be defined by your {@link +android.app.ActionBar.TabListener} callback methods. When a tab is selected, it receives a call to +{@link android.app.ActionBar.TabListener#onTabSelected onTabSelected()} and that's where you should +add the appropriate fragment to the designated view in your layout, using {@link +android.app.FragmentTransaction#add add()} with the provided {@link +android.app.FragmentTransaction}. Likewise, when a tab is deselected (because another tab becomes +selected), you should remove that fragment from the layout, using {@link +android.app.FragmentTransaction#remove remove()}.</p> + +<p class="note"><strong>Note:</strong> You <strong>do not</strong> need +to call {@link android.app.FragmentTransaction#commit} for these transactions. You also +<strong>cannot</strong> add these fragment transactions to the back stack.</p> + +<p>If your activity is stopped, you should retain the currently selected tab with the saved state so +that when the user returns to your application, you can open the tab. When it's time to save the +state, you can query the currently selected tab with {@link +android.app.ActionBar#getSelectedNavigationIndex()}. This returns the index position of the selected +tab.</p> + +<p class="caution"><strong>Caution:</strong> It's important that you save +the state of each fragment as necessary, so when the user switches fragments with the tabs, +then returns to a previous fragment, it appears the way they left. For information about saving +the state of your fragment, see the <a +href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p> + + + +<h2 id="Dropdown">Adding Drop-down Navigation</h2> + +<p>As another mode of navigation within your activity, you can provide a drop-down list in the +Action Bar. For example, the drop-down list can provide alternative modes for sorting the content in +the activity or switching the user's account.</p> + +<!-- +<div class="figure" style="width:135px"> + <img src="{@docRoot}images/ui/actionbar-dropdown.png" alt="" /> + <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a drop-down navigation list in the +Action Bar.</p> +</div> +--> + +<p>Here's a quick list of what you must do to enable drop-down navigation:</p> + +<ol> + <li>Create a {@link android.widget.SpinnerAdapter} that provides the +list of selectable items for the list and the layout to use when drawing each item in the list.</li> + <li>Implement {@link android.app.ActionBar.OnNavigationListener} to define the behavior when the +user selects an item from the list.</li> + <li>Turn on navigation mode for the Action Bar with {@link +android.app.ActionBar#setNavigationMode setNavigationMode()}. For example: +<pre> +ActionBar actionBar = getActionBar(); +actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); +</pre> + <p>You should perform this during your activity's {@link android.app.Activity#onCreate +onCreate()} method.</p> + </li> + <li>Following that, set the callback for your drop-down list with {@link +android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}. For example: +<pre> +actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback); +</pre> +<p>This method takes your {@link android.widget.SpinnerAdapter} and {@link +android.app.ActionBar.OnNavigationListener}. More about these next.</p> +</li> +</ol> + +<p>That's the basic setup. The {@link android.widget.SpinnerAdapter} and {@link +android.app.ActionBar.OnNavigationListener} is where most of the work is done. There are many ways +you can implement these to define the functionality for your drop-down navigation. Implementing +various types of {@link android.widget.SpinnerAdapter} is beyond the scope of this +document—you should refer to the class refrence for more information about implementing it or +extending an existing implementation. However, below is a simple example for a {@link +android.widget.SpinnerAdapter} and {@link android.app.ActionBar.OnNavigationListener} to get you +started.</p> + + +<h3 id="Spinner">Example: simple SpinnerAdapter</h3> + +<p>{@link android.widget.SpinnerAdapter} is an interface that you can implement to provide +content for the list and is where your implementation for the drop-down list can be heavily +customized. Android includes some useful implementations that you can extend, such as {@link +android.widget.ArrayAdapter} and {@link +android.widget.SimpleCursorAdapter}. For example, here's an easy way to create a {@link +android.widget.SpinnerAdapter} with {@link android.widget.ArrayAdapter}, using a string array +from resources:</p> + +<pre> +SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list, + android.R.layout.simple_spinner_dropdown_item); +</pre> + +<p>This is now ready to be given to {@link +android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from +above.</p> + +<p>A <a href="{@docRoot}guide/topics/resources/string-resource.html#StringArray">string array</a> +defined as a resource looks like this:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string-array name="action_list"> + <item>Mercury</item> + <item>Venus</item> + <item>Earth</item> + </string-array> +</pre> +</pre> + + +<h3 id="OnNavigationListener">Example: simple OnNavigationListener</h3> + +<p>Your implementation of {@link android.app.ActionBar.OnNavigationListener} is where you handle +fragment changes or other modifications to your activity when the user selects an item from the +drop-down list. There's only one callback method to implement: {@link +android.app.ActionBar.OnNavigationListener#onNavigationItemSelected onNavigationItemSelected()}.</p> + +<p>The {@link +android.app.ActionBar.OnNavigationListener#onNavigationItemSelected onNavigationItemSelected()} +method receives the position of the item in the list and an item ID provided by the {@link +android.widget.SpinnerAdapter}.</p> + +<p>Here's an example that instantiates an anonymous implementation of {@link +android.app.ActionBar.OnNavigationListener}, which inserts a {@link android.app.Fragment} into the +layout container identified by {@code R.id.fragment_container}:</p> + +<pre> +mOnNavigationListener = new OnNavigationListener() { + // Get the same strings provided for the drop-down's ArrayAdapter + String[] strings = getResources().getStringArray(R.array.action_list); + + @Override + public boolean onNavigationItemSelected(int position, long itemId) { + // Create new fragment from our own Fragment class + ListContentFragment newFragment = new ListContentFragment(); + FragmentTransaction ft = openFragmentTransaction(); + // Replace whatever is in the fragment container with this fragment + // and give the fragment a tag name equal to the string at the position selected + ft.replace(R.id.fragment_container, newFragment, strings[position]); + // Apply changes + ft.commit(); + return true; + } +}; +</pre> + +<p>This instance of {@link android.app.ActionBar.OnNavigationListener} can be given to {@link +android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from +above.</p> + +<p>In this example, the fragment added is given a tag that can uniquely identify the fragment. +For this example, the {@code ListContentFragment} class used uses this tag as +the text for a {@link android.widget.TextView} in the fragment's layout. Here's how it's done:</p> + +<pre> +public class ListContentFragment extends Fragment { + private String mText; + + @Override + public void onAttach(Activity activity) { + // This is the first callback received; here we can set the text for + // the fragment as defined by the tag specified during the fragment transaction + super.onAttach(activity); + mText = getTag(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // This is called to define the layout for the fragment; + // we just create a TextView and set its text to be the fragment tag + TextView text = new TextView(getActivity()); + text.setText(mText); + return text; + } +} +</pre> + + + + diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd index f95a89b..c348767 100644 --- a/docs/html/guide/topics/ui/declaring-layout.jd +++ b/docs/html/guide/topics/ui/declaring-layout.jd @@ -47,11 +47,11 @@ application can create View and ViewGroup objects (and manipulate their properti Plugin for Eclipse</a> offers a layout preview of your XML — with the XML file opened, select the <strong>Layout</strong> tab.</li> <li>You should also try the - <a href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Hierarchy Viewer</a> tool, + <a href="{@docRoot}guide/developing/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a> tool, for debugging layouts — it reveals layout property values, draws wireframes with padding/margin indicators, and full rendered views while you debug on the emulator or device.</li> - <li>The <a href="{@docRoot}guide/developing/tools/layoutopt.html">layoutopt</a> tool lets + <li>The <a href="{@docRoot}guide/developing/debugging/debugging-ui.html#layoutopt">layoutopt</a> tool lets you quickly analyze your layouts and hierarchies for inefficiencies or other problems.</li> </div> </div> @@ -119,7 +119,7 @@ for your Activity like so:</p> <pre> public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView.(R.layout.main_layout); + setContentView(R.layout.main_layout); } </pre> @@ -190,10 +190,12 @@ layout parameters for the View that are appropriate for the ViewGroup in which i <p>Every ViewGroup class implements a nested class that extends {@link android.view.ViewGroup.LayoutParams}. This subclass contains property types that define the size and position for each child view, as -appropriate for the view group. As you can see in the figure below, the parent +appropriate for the view group. As you can see in figure 1, the parent view group defines layout parameters for each child view (including the child view group).</p> <img src="{@docRoot}images/layoutparams.png" alt="" height="300" align="center"/> +<p class="img-caption"><strong>Figure 1.</strong> Visualization of a view hierarchy with layout +parameters associated with each view.</p> <p>Note that every LayoutParams subclass has its own syntax for setting values. Each child element must define LayoutParams that are appropriate for its parent, diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd index 1a997f9..d50e1cb 100644 --- a/docs/html/guide/topics/ui/dialogs.jd +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -22,20 +22,32 @@ parent.link=index.html </li> <li><a href="#CustomDialog">Creating a Custom Dialog</a></li> </ol> - + <h2>Key classes</h2> <ol> <li>{@link android.app.Dialog}</li> + <li>{@link android.app.AlertDialog}</li> + <li>{@link android.app.DialogFragment}</li> + </ol> + + <h2>Related tutorials</h2> + <ol> + <li><a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Hello +DatePicker</a></li> + <li><a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Hello +TimePicker</a></li> </ol> </div> </div> <p>A dialog is usually a small window that appears in front of the current Activity. -The underlying Activity loses focus and the dialog accepts all user interaction. -Dialogs are normally used -for notifications and short activities that directly relate to the application in progress.</p> +The underlying Activity loses focus and the dialog accepts all user interaction. Dialogs are +normally used for notifications that should interupt the user and to perform short tasks that +directly relate to the application in progress (such as a progress bar or a login prompt).</p> -<p>The Android API supports the following types of {@link android.app.Dialog} objects:</p> +<p>The {@link android.app.Dialog} class is the base class for creating dialogs. However, you +typically should not instantiate a {@link android.app.Dialog} directly. Instead, you should use one +of the following subclasses:</p> <dl> <dt>{@link android.app.AlertDialog}</dt> <dd>A dialog that can manage zero, one, two, or three buttons, and/or a list of @@ -473,18 +485,25 @@ public class NotificationTest extends Activity { progressDialog = new ProgressDialog(NotificationTest.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Loading..."); - progressThread = new ProgressThread(handler); - progressThread.start(); return progressDialog; default: return null; } } + @Override + protected void onPrepareDialog(int id, Dialog dialog) { + switch(id) { + case PROGRESS_DIALOG: + progressDialog.setProgress(0); + progressThread = new ProgressThread(handler); + progressThread.start(); + } + // Define the Handler that receives messages from the thread and update the progress final Handler handler = new Handler() { public void handleMessage(Message msg) { - int total = msg.getData().getInt("total"); + int total = msg.arg1; progressDialog.setProgress(total); if (total >= 100){ dismissDialog(PROGRESS_DIALOG); @@ -515,9 +534,7 @@ public class NotificationTest extends Activity { Log.e("ERROR", "Thread Interrupted"); } Message msg = mHandler.obtainMessage(); - Bundle b = new Bundle(); - b.putInt("total", total); - msg.setData(b); + msg.arg1 = total; mHandler.sendMessage(msg); total++; } diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd index 42790b6..d1c0ff8 100644 --- a/docs/html/guide/topics/ui/menus.jd +++ b/docs/html/guide/topics/ui/menus.jd @@ -36,6 +36,7 @@ parent.link=index.html <h2>See also</h2> <ol> + <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a></li> <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li> </ol> </div> @@ -48,20 +49,9 @@ for you to provide application menus in your application.</p> <p>Android provides three types of application menus:</p> <dl> <dt><strong>Options Menu</strong></dt> - <dd>The primary menu for an Activity, which appears when the user presses - the device MENU key. Within the Options Menu are two groups: - <dl style="margin-top:1em"> - <dt><em>Icon Menu</em></dt> - <dd>The menu items visible at the bottom of the screen - at the press of the MENU key. It supports a maximum of six menu items. - These are the only menu items that support icons and the only menu items that <em>do not</em> support - checkboxes or radio buttons.</dd> - <dt><em>Expanded Menu</em></dt> - <dd>The vertical list of menu items exposed by the "More" menu item in the Icon Menu. - When the Icon Menu is full, the expanded menu is comprised of the sixth - menu item and the rest.</dd> - </dl> - </dd> + <dd>The primary collection of menu items for an Activity that is associated with the device MENU +key. To provide instant access to select menu items, you can place some items in the <a +href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, if available.</dd> <dt><strong>Context Menu</strong></dt> <dd>A floating list of menu items that appears when the user performs a long-press on a View. </dd> @@ -74,7 +64,7 @@ Menu or a context menu. A submenu item cannot support a nested submenu. </dd> <h2 id="xml">Defining Menus</h2> -<p>Instead of instantiating {@link android.view.Menu} objects in your application code, you should +<p>Instead of instantiating a {@link android.view.Menu} in your application code, you should define a menu and all its items in an XML <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, then inflate the menu resource (load it as a programmable object) in your application code. Defining your menus in XML is @@ -104,9 +94,9 @@ href="#groups">Menu groups</a>.</dd> <item android:id="@+id/new_game" android:icon="@drawable/ic_new_game" android:title="@string/new_game" /> - <item android:id="@+id/quit" - android:icon="@drawable/ic_quit" - android:title="@string/quit" /> + <item android:id="@+id/help" + android:icon="@drawable/ic_help" + android:title="@string/help" /> </menu> </pre> @@ -161,36 +151,64 @@ creating an option menu is discussed more in the next section.)</p> </div> -<p>The Options Menu is where you should include basic application functions -and necessary navigation items (for example, a button -to open application settings). The user -can open the Options Menu with the device MENU key. -Figure 1 shows a screenshot of an Options Menu.</p> +<p>The Options Menu is where you should include basic application functions and necessary navigation +items (for example, a button to open the application settings). Items in the Options Menu are +accessible in two distinct ways: in the Action Bar and in the menu revealed by the MENU +key.</p> + +<p>The Action Bar is an optional widget that appears at the top of the activity in place of the +title bar. It can display several menu items that you choose from the Options Menu, but items in +the Action Bar display only an icon (no title text). Users can reveal the other menu items in the +Options Menu with the MENU key.</p> -<p>When opened, the first visible portion of the Options Menu is called the Icon Menu. It -holds the first six menu items. -If you add more than six items to the Options Menu, Android places the sixth item and those after it -into the Expanded Menu, which the user can open with the "More" menu item.</p> +<p>If you include the Action Bar in your activity, the menu items that are not placed in the Action +Bar can appear in two different styles:</p> +<dl> + <dt>Action Bar Menu</dt> + <dd>If the device has an extra-large screen ({@code xlarge}), then all items in the Options Menu +that are not placed in the Action Bar are placed into a drop-down list at the right side of the +Action Bar, with icons and title text. The user can reveal the drop-down list by pressing the +drop-down icon in the Action Bar or the MENU key.</dd> + <dt>Standard Options Menu</dt> + <dd>If the device <em>does not</em> have an extra-large screen, then all items in the Options +Menu that are not placed in the Action Bar are placed into the Standard Options Menu at the bottom +of the activity. The user can reveal the standard Options Menu by pressing the MENU key. + <p>The first visible portion of the Standard Options Menu is called the Icon Menu. +It holds the first six menu items (excluding any added to the Action Bar), with icons and title +text. If there are more than six items, Android adds a "More" item as the sixth menu item and places +the remaining items into the Expanded Menu, which the user can open by selecting "More". The +Expanded Menu displays menu items only by their title text (no icon)</p> + </dd> +</dl> <p>When the user opens the Options Menu for the first time, Android calls your Activity's {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} method. Override this method in your Activity and populate the {@link android.view.Menu} that is passed into the method. Populate the {@link android.view.Menu} by inflating a menu resource as described in <a -href="#Inflating">Inflating a Menu Resource</a>. (You can -also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int) -add()} to add menu items.)</p> +href="#Inflating">Inflating a Menu Resource</a>. For example:</p> -<p>When the user selects a menu item from the Options Menu, the system calls your Activity's +<pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.game_menu, menu); + return true; +} +</pre> + +<p>(You can also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int) +add()} to add items to the {@link android.view.Menu}.)</p> + +<p>When the user selects a menu item from the Options Menu (including items selected from the +Action Bar), the system calls your Activity's {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method. This method passes the {@link android.view.MenuItem} that the user selected. You can identify the menu item by calling {@link android.view.MenuItem#getItemId()}, which returns the unique ID for the menu item (defined by the {@code android:id} attribute in the menu resource or with an integer passed to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match this ID -against known menu items and perform the appropriate action.</p> - -<p>For example:</p> +against known menu items and perform the appropriate action. For example:</p> <pre> @Override @@ -200,8 +218,8 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.new_game: newGame(); return true; - case R.id.quit: - quit(); + case R.id.help: + showHelp(); return true; default: return super.onOptionsItemSelected(item); @@ -224,8 +242,8 @@ an Activity that implements nothing except the {@link android.app.Activity#onCre onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} methods. Then extend this class for each Activity that should share the same Options Menu. This way, you have to manage only one set of code for handling menu -actions and each decendent class inherits the menu behaviors.<br/><br/> -If you want to add menu items to one of your decendent activities, +actions and each descendant class inherits the menu behaviors.<br/><br/> +If you want to add menu items to one of your descendant activities, override {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} in that Activity. Call {@code super.onCreateOptionsMenu(menu)} so the original menu items are created, then add new menu items with {@link @@ -542,7 +560,7 @@ hardware keyboard. Shortcuts cannot be added to items in a Context Menu.</p> <h3 id="intents">Intents for menu items</h3> <p>Sometimes you'll want a menu item to launch an Activity using an Intent (whether it's an -Actvitity in your application or another application). When you know the Intent you want to use and +Activity in your application or another application). When you know the Intent you want to use and have a specific menu item that should initiate the Intent, you can execute the Intent with {@link android.app.Activity#startActivity(Intent) startActivity()} during the appropriate on-item-selected callback method (such as the {@link android.app.Activity#onOptionsItemSelected(MenuItem) |