Android SDK 1.5 Eng.

看SDK的文档时,有时候网站http://developer.android.com登录不上去,就把Android新的SDK内容放在这里,共自己和别人参考吧。

 

 

开始...

 

 

  • Android Basics

  • Framework Topics

  • Developing

  • Publishing

  • Best Practices

  • Tutorials and Sample Code

  • Appendix

  • The Developer's Guide

    Welcome to the Android Dev Guide! The Dev Guide is a practical introduction to developing applications for Android. It explores the concepts behind Android, the framework for constructing an application, and the tools for developing, testing, and publishing software for the platform.

    The Dev Guide holds most of the documentation for the Android platform, except for reference material on the framework API. For API specifications, go to the Reference tab above.

    As you can see in the panel on the left, the Dev Guide is divided into a handful of sections. They are:

     

    Android Basics
    An initial orientation to Android — what it is, what it offers, and how your application fits in.
    Framework Topics
    Discussions of particular parts of the Android framework and API. For an overview of the framework, begin with Application Fundamentals. Then explore other topics — from designing a user interface and setting up resources to storing data and using permissions — as needed.
    Developing
    Directions for using Android's development and debugging tools, and for testing the results.
    Publishing
    Instructions on how to prepare your application for deployment and how to publish it when it's ready.
    Best Practices
    Recommendations on preferred techniques for writing applications that perform efficiently and work well for the user.
    Tutorials and Samples
    Step-by-step tutorials and sample code demonstrating how an Android application is constructed.
    Appendix
    Reference information and specifications, as well as FAQs, a glossary of terms, and other information.

    The first step in programming for Android is downloading the SDK (software development kit). For instructions and information about the kit, go to the SDK tab above.

    After you have the SDK, begin by looking over the Dev Guide. If you want to start by getting a quick look at the code, the short Hello World tutorial walks you through a standard "Hello, World" application as it would be written for the Android platform. The Application Fundamentals document is a good place to start for an understanding of the application framework.

    For additional help, consider joining one or more of the Android discussion groups. Go to the Community tab above for more information.

    To return to this page later, just click the "Dev Guide" tab while any Dev Guide page is loaded.

     

     

    What is Android?

    Android is a software stack for mobile devices that includes an operating system, middleware and key applications. The Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.

    Features

    • Application framework enabling reuse and replacement of components
    • Dalvik virtual machine optimized for mobile devices
    • Integrated browser based on the open source WebKit engine
    • Optimized graphics powered by a custom 2D graphics library; 3D graphics based on the OpenGL ES 1.0 specification (hardware acceleration optional)
    • SQLite for structured data storage
    • Media support for common audio, video, and still image formats (MPEG4, H.264, MP3, AAC, AMR, JPG, PNG, GIF)
    • GSM Telephony (hardware dependent)
    • Bluetooth, EDGE, 3G, and WiFi (hardware dependent)
    • Camera, GPS, compass, and accelerometer (hardware dependent)
    • Rich development environment including a device emulator, tools for debugging, memory and performance profiling, and a plugin for the Eclipse IDE

    Android Architecture

    The following diagram shows the major components of the Android operating system. Each section is described in more detail below.

    Android System Architecture

    Applications

    Android will ship with a set of core applications including an email client, SMS program, calendar, maps, browser, contacts, and others. All applications are written using the Java programming language.

    Application Framework

    Developers have full access to the same framework APIs used by the core applications. The application architecture is designed to simplify the reuse of components; any application can publish its capabilities and any other application may then make use of those capabilities (subject to security constraints enforced by the framework). This same mechanism allows components to be replaced by the user.

    Underlying all applications is a set of services and systems, including:

    • A rich and extensible set of Views that can be used to build an application, including lists, grids, text boxes, buttons, and even an embeddable web browser
    • Content Providers that enable applications to access data from other applications (such as Contacts), or to share their own data
    • A Resource Manager, providing access to non-code resources such as localized strings, graphics, and layout files
    • A Notification Manager that enables all applications to display custom alerts in the status bar
    • An Activity Manager that manages the lifecycle of applications and provides a common navigation backstack

    For more details and a walkthrough of an application, see the Notepad Tutorial.

    Libraries

    Android includes a set of C/C++ libraries used by various components of the Android system. These capabilities are exposed to developers through the Android application framework. Some of the core libraries are listed below:

    • System C library - a BSD-derived implementation of the standard C system library (libc), tuned for embedded Linux-based devices
    • Media Libraries - based on PacketVideo's OpenCORE; the libraries support playback and recording of many popular audio and video formats, as well as static image files, including MPEG4, H.264, MP3, AAC, AMR, JPG, and PNG
    • Surface Manager - manages access to the display subsystem and seamlessly composites 2D and 3D graphic layers from multiple applications
    • LibWebCore - a modern web browser engine which powers both the Android browser and an embeddable web view
    • SGL - the underlying 2D graphics engine
    • 3D libraries - an implementation based on OpenGL ES 1.0 APIs; the libraries use either hardware 3D acceleration (where available) or the included, highly optimized 3D software rasterizer
    • FreeType - bitmap and vector font rendering
    • SQLite - a powerful and lightweight relational database engine available to all applications

    Android Runtime

    Android includes a set of core libraries that provides most of the functionality available in the core libraries of the Java programming language.

    Every Android application runs in its own process, with its own instance of the Dalvik virtual machine. Dalvik has been written so that a device can run multiple VMs efficiently. The Dalvik VM executes files in the Dalvik Executable (.dex) format which is optimized for minimal memory footprint. The VM is register-based, and runs classes compiled by a Java language compiler that have been transformed into the .dex format by the included "dx" tool.

    The Dalvik VM relies on the Linux kernel for underlying functionality such as threading and low-level memory management.

    Linux Kernel

    Android relies on Linux version 2.6 for core system services such as security, memory management, process management, network stack, and driver model. The kernel also acts as an abstraction layer between the hardware and the rest of the software stack.

     

    Application Fundamentals

    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 aapt tool into an Android package, an archive file marked by an .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 .apk file is considered to be one application.

    In many ways, each Android application lives in its own world:

    • By default, every application runs in its own Linux process. Android starts the process when any of the application's code needs to be executed, and shuts down the process when it's no longer needed and system resources are required by other applications.
    • Each process has its own Java virtual machine (VM), so application code runs in isolation from the code of all other applications.
    • By default, each application is assigned a unique Linux user ID. Permissions are set so that the application's files are visible only that user, only to the application itself — although there are ways to export them to other applications as well.

    It's possible to arrange for two applications to share the same user ID, in which case they will be able to see each other's files. To conserve system resources, applications with the same ID can also arrange to run in the same Linux process, sharing the same VM.

    Application Components

    A central feature of Android is that one application can make use of elements of other applications (provided those applications permit it). For example, if your application needs to display a scrolling list of images and another application has developed a suitable scroller and made it available to others, you can call upon that scroller to do the work, rather than develop your own. Your application doesn't incorporate the code of the other application or link to it. Rather, it simply starts up that piece of the other application when the need arises.

    For this to work, the system must be able to start an application process when any part of it is needed, and instantiate the Java objects for that part. Therefore, unlike applications on most other systems, Android applications don't have a single entry point for everything in the application (no main() function, for example). Rather, they have essential components that the system can instantiate and run as needed. There are four types of components:

    Activities
    An activity presents a visual user interface for one focused endeavor the user can undertake. For example, an activity might present a list of menu items users can choose from or it might display photographs along with their captions. A text messaging application might have one activity that shows a list of contacts to send messages to, a second activity to write the message to the chosen contact, and other activities to review old messages or change settings. Though they work together to form a cohesive user interface, each activity is independent of the others. Each one is implemented as a subclass of the Activity base class.

    An application might consist of just one activity or, like the text messaging application just mentioned, it may contain several. What the activities are, and how many there are depends, of course, on the application and its design. Typically, one of the activities is marked as the first one that should be presented to the user when the application is launched. Moving from one activity to another is accomplished by having the current activity start the next one.

    Each activity is given a default window to draw in. Typically, the window fills the screen, but it might be smaller than the screen and float on top of other windows. An activity can also make use of additional windows — for example, a pop-up dialog that calls for a user response in the midst of the activity, or a window that presents users with vital information when they select a particular item on-screen.

    The visual content of the window is provided by a hierarchy of views — objects derived from the base View class. Each view controls a particular rectangular space within the window. Parent views contain and organize the layout of their children. Leaf views (those at the bottom of the hierarchy) draw in the rectangles they control and respond to user actions directed at that space. Thus, views are where the activity's interaction with the user takes place. For example, a view might display a small image and initiate an action when the user taps that image. Android has a number of ready-made views that you can use — including buttons, text fields, scroll bars, menu items, check boxes, and more.

    A view hierarchy is placed within an activity's window by the Activity.setContentView() method. The content view is the View object at the root of the hierarchy. (See the separate User Interface document for more information on views and the hierarchy.)

     

    Services
    A service doesn't have a visual user interface, but rather runs in the background for an indefinite period of time. For example, a service might play background music as the user attends to other matters, or it might fetch data over the network or calculate something and provide the result to activities that need it. Each service extends the Service base class.

    A prime example is a media player playing songs from a play list. The player application would probably have one or more activities that allow the user to choose songs and start playing them. However, the music playback itself would not be handled by an activity because users will expect the music to keep playing even after they leave the player and begin something different. To keep the music going, the media player activity could start a service to run in the background. The system would then keep the music playback service running even after the activity that started it leaves the screen.

    It's possible to connect to (bind to) an ongoing service (and start the service if it's not already running). While connected, you can communicate with the service through an interface that the service exposes. For the music service, this interface might allow users to pause, rewind, stop, and restart the playback.

    Like activities and the other components, services run in the main thread of the application process. So that they won't block other components or the user interface, they often spawn another thread for time-consuming tasks (like music playback). See Processes and Threads, later.

    Broadcast receivers
    A broadcast receiver is a component that does nothing but receive and react to broadcast announcements. Many broadcasts originate in system code — for example, announcements that the timezone has changed, that the battery is low, that a picture has been taken, or that the user changed a language preference. Applications can also initiate broadcasts — for example, to let other applications know that some data has been downloaded to the device and is available for them to use.

    An application can have any number of broadcast receivers to respond to any announcements it considers important. All receivers extend the BroadcastReceiver base class.

    Broadcast receivers do not display a user interface. However, they may start an activity in response to the information they receive, or they may use the NotificationManager to alert the user. Notifications can get the user's attention in various ways — flashing the backlight, vibrating the device, playing a sound, and so on. They typically place a persistent icon in the status bar, which users can open to get the message.

    Content providers
    A content provider makes a specific set of the application's data available to other applications. The data can be stored in the file system, in an SQLite database, or in any other manner that makes sense. The content provider extends the ContentProvider base class to implement a standard set of methods that enable other applications to retrieve and store data of the type it controls. However, applications do not call these methods directly. Rather they use a ContentResolver object and call its methods instead. A ContentResolver can talk to any content provider; it cooperates with the provider to manage any interprocess communication that's involved.

    See the separate Content Providers document for more information on using content providers.

    Whenever there's a request that should be handled by a particular component, Android makes sure that the application process of the component is running, starting it if necessary, and that an appropriate instance of the component is available, creating the instance if necessary.

    Activating components: intents

    Content providers are activated when they're targeted by a request from a ContentResolver. The other three components — activities, services, and broadcast receivers — are activated by asynchronous messages called intents. An intent is an Intent object that holds the content of the message. For activities and services, it names the action being requested and specifies the URI of the data to act on, among other things. For example, it might convey a request for an activity to present an image to the user or let the user edit some text. For broadcast receivers, the Intent object names the action being announced. For example, it might announce to interested parties that the camera button has been pressed.

    There are separate methods for activiating each type of component:

    • An activity is launched (or given something new to do) by passing an Intent object to Context.startActivity() or Activity.startActivityForResult(). The responding activity can look at the initial intent that caused it to be launched by calling its getIntent() method. Android calls the activity's onNewIntent() method to pass it any subsequent intents.

      One activity often starts the next one. If it expects a result back from the activity it's starting, it calls startActivityForResult() instead of startActivity(). For example, if it starts an activity that lets the user pick a photo, it might expect to be returned the chosen photo. The result is returned in an Intent object that's passed to the calling activity's onActivityResult() method.

    • A service is started (or new instructions are given to an ongoing service) by passing an Intent object to Context.startService(). Android calls the service's onStart() method and passes it the Intent object.

      Similarly, an intent can be passed to Context.bindService() to establish an ongoing connection between the calling component and a target service. The service receives the Intent object in an onBind() call. (If the service is not already running, bindService() can optionally start it.) For example, an activity might establish a connection with the music playback service mentioned earlier so that it can provide the user with the means (a user interface) for controlling the playback. The activity would call bindService() to set up that connection, and then call methods defined by the service to affect the playback.

      A later section, Remote procedure calls, has more details about binding to a service.

    • An application can initiate a broadcast by passing an Intent object to methods like Context.sendBroadcast(), Context.sendOrderedBroadcast(), and Context.sendStickyBroadcast() in any of their variations. Android delivers the intent to all interested broadcast receivers by calling their onReceive() methods.

    For more on intent messages, see the separate article, Intents and Intent Filters.

    Shutting down components

    A content provider is active only while it's responding to a request from a ContentResolver. And a broadcast receiver is active only while it's responding to a broadcast message. So there's no need to explicitly shut down these components.

    Activities, on the other hand, provide the user interface. They're in a long-running conversation with the user and may remain active, even when idle, as long as the conversation continues. Similarly, services may also remain running for a long time. So Android has methods to shut down activities and services in an orderly way:

    • An activity can be shut down by calling its finish() method. One activity can shut down another activity (one it started with startActivityForResult()) by calling finishActivity().
    • A service can be stopped by calling its stopSelf() method, or by calling Context.stopService().

    Components might also be shut down by the system when they are no longer being used or when Android must reclaim memory for more active components. A later section, Component Lifecycles, discusses this possibility and its ramifications in more detail.

    The manifest file

    Before Android can start an application component, it must learn that the component exists. Therefore, applications declare their components in a manifest file that's bundled into the Android package, the .apk file that also holds the application's code, files, and resources.

    The manifest is a structured XML file and is always named AndroidManifest.xml for all applications. It does a number of things in addition to declaring the application's components, such as naming any libraries the application needs to be linked against (besides the default Android library) and identifying any permissions the application expects to be granted.

    But the principal task of the manifest is to inform Android about the application's components. For example, an activity might be declared as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest . . . >
        <application . . . >
            <activity android:name="com.example.project.FreneticActivity"
                      android:icon="@drawable/small_pic.png"
                      android:label="@string/freneticLabel" 
                      . . .  >
            </activity>
            . . .
        </application>
    </manifest>

    The name attribute of the <activity> element names the Activity subclass that implements the activity. The icon and label attributes point to resource files containing an icon and label that can be displayed to users to represent the activity.

    The other components are declared in a similar way — <service> elements for services, <receiver> elements for broadcast receivers, and <provider> 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 declared in the manifest, or they can be created dynamically in code (as BroadcastReceiver objects) and registered with the system by calling Context.registerReceiver().

    For more on how to structure a manifest file for your application, see The AndroidManifest.xml File.

    Intent filters

    An Intent object can explicitly name a target component. If it does, Android finds that component (based on the declarations in the manifest file) and activates it. But if a target is not explicitly named, Android must locate the best component to respond to the intent. It does so by comparing the Intent object to the intent filters of potential targets. A component's intent filters inform Android of the kinds of intents the component is able to handle. Like other essential information about the component, they're declared in the manifest file. Here's an extension of the previous example that adds two intent filters to the activity:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest . . . >
        <application . . . >
            <activity android:name="com.example.project.FreneticActivity"
                      android:icon="@drawable/small_pic.png"
                      android:label="@string/freneticLabel" 
                      . . .  >
                <intent-filter . . . >
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                <intent-filter . . . >
                    <action android:name="com.example.project.BOUNCE" />
                    <data android:mimeType="image/jpeg" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
            . . .
        </application>
    </manifest>

    The first filter in the example — the combination of the action "android.intent.action.MAIN" and the category "android.intent.category.LAUNCHER" — is a common one. It marks the activity as one that should be represented in the application launcher, the screen listing applications users can launch on the device. In other words, the activity is the entry point for the application, the initial one users would see when they choose the application in the launcher.

    The second filter declares an action that the activity can perform on a particular type of data.

    A component can have any number of intent filters, each one declaring a different set of capabilities. If it doesn't have any filters, it can be activated only by intents that explicitly name the component as the target.

    For a broadcast receiver that's created and registered in code, the intent filter is instantiated directly as an IntentFilter object. All other filters are set up in the manifest.

    For more on intent filters, see a separate document, Intents and Intent Filters.

    Activities and Tasks

    As noted earlier, one activity can start another, including one defined in a different application. Suppose, for example, that you'd like to let users display a street map of some location. There's already an activity that can do that, so all your activity needs to do is put together an Intent object with the required information and pass it to startActivity(). The map viewer will display the map. When the user hits the BACK key, your activity will reappear on screen.

    To the user, it will seem as if the map viewer is part of the same application as your activity, even though it's defined in another application and runs in that application's process. Android maintains this user experience by keeping both activities in the same task. Simply put, a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack. The root activity in the stack is the one that began the task — typically, it's an activity the user selected in the application launcher. The activity at the top of the stack is one that's currently running — the one that is the focus for user actions. When one activity starts another, the new activity is pushed on the stack; it becomes the running activity. The previous activity remains in the stack. When the user presses the BACK key, the current activity is popped from the stack, and the previous one resumes as the running activity.

    The stack contains objects, so if a task has more than one instance of the same Activity subclass open — multiple map viewers, for example — the stack has a separate entry for each instance. Activities in the stack are never rearranged, only pushed and popped.

    A task is a stack of activities, not a class or an element in the manifest file. So there's no way to set values for a task independently of its activities. Values for the task as a whole are set in the root activity. For example, the next section will talk about the "affinity of a task"; that value is read from the affinity set for the task's root activity.

    All the activities in a task move together as a unit. The entire task (the entire activity stack) can be brought to the foreground or sent to the background. Suppose, for instance, that the current task has four activities in its stack — three under the current activity. The user presses the HOME key, goes to the application launcher, and selects a new application (actually, a new task). The current task goes into the background and the root activity for the new task is displayed. Then, after a short period, the user goes back to the home screen and again selects the previous application (the previous task). That task, with all four activities in the stack, comes forward. When the user presses the BACK key, the screen does not display the activity the user just left (the root activity of the previous task). Rather, the activity on the top of the stack is removed and the previous activity in the same task is displayed.

    The behavior just described is the default behavior for activities and tasks. But there are ways to modify almost all aspects of it. The association of activities with tasks, and the behavior of an activity within a task, is controlled by the interaction between flags set in the Intent object that started the activity and attributes set in the activity's <activity> element in the manifest. Both requester and respondent have a say in what happens.

    In this regard, the principal Intent flags are:

    FLAG_ACTIVITY_NEW_TASK
    FLAG_ACTIVITY_CLEAR_TOP
    FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    FLAG_ACTIVITY_SINGLE_TOP

    The principal <activity> attributes are:

    taskAffinity
    launchMode
    allowTaskReparenting
    clearTaskOnLaunch
    alwaysRetainTaskState
    finishOnTaskLaunch

    The following sections describe what some of these flags and attributes do, how they interact, and what considerations should govern their use.

    Affinities and new tasks

    By default, all the activities in an application have an affinity for each other — that is, there's a preference for them all to belong to the same task. However, an individual affinity can be set for each activity with the taskAffinity attribute of the <activity> element. Activities defined in different applications can share an affinity, or activities defined in the same application can be assigned different affinities. The affinity comes into play in two circumstances: When the Intent object that launches an activity contains the FLAG_ACTIVITY_NEW_TASK flag, and when an activity has its allowTaskReparenting attribute set to "true".

    The FLAG_ACTIVITY_NEW_TASK flag
    As described earlier, a new activity is, by default, launched into the task of the activity that called startActivity(). It's pushed onto the same stack as the caller. However, if the Intent object passed to startActivity() contains the FLAG_ACTIVITY_NEW_TASK flag, the system looks for a different task to house the new activity. Often, as the name of the flag implies, 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.
    The allowTaskReparenting attribute
    If an activity has its allowTaskReparenting attribute set to " true", it can move from the task it starts in to the task it has an affinity for when that task comes to the fore. 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 affinity) and it allows reparenting. One of your activities starts the weather reporter, so it initially belongs to the same task as your activity. However, when the travel application next comes forward, the weather reporter will be reassigned to and displayed with that task.

    If an .apk file contains more than one "application" from the user's point of view, you will probably want to assign different affinities to the activities associated with each of them.

    Launch modes

    There are four different launch modes that can be assigned to an <activity> element's launchMode attribute:

    "standard" (the default mode)
    "singleTop"
    "singleTask"
    "singleInstance"

    The modes differ from each other on these four points:

    • Which task will hold the activity that responds to the intent. For the "standard" and "singleTop" modes, it's the task that originated the intent (and called startActivity()) — unless the Intent object contains the FLAG_ACTIVITY_NEW_TASK flag. In that case, a different task is chosen as described in the previous section, Affinities and new tasks.

      In contrast, the "singleTask" and "singleInstance" modes mark activities that are always at the root of a task. They define a task; they're never launched into another task.

    • Whether there can be multiple instances of the activity. A "standard" or "singleTop" activity can be instantiated many times. They can belong to multiple tasks, and a given task can have multiple instances of the same activity.

      In contrast, "singleTask" and "singleInstance" activities are limited to just one instance. Since these activities are at the root of a task, this limitation means that there is never more than a single instance of the task on the device at one time.

    • Whether the instance can have other activities in its task. A "singleInstance" activity stands alone as the only activity in its task. If it starts another activity, that activity will be launched into a different task regardless of its launch mode — as if FLAG_ACTIVITY_NEW_TASK was in the intent. In all other respects, the "singleInstance" mode is identical to "singleTask".

      The other three modes permit multiple activities to belong to the task. A "singleTask" activity will always be the root activity of the task, but it can start other activities that will be assigned to its task. Instances of "standard" and "singleTop" activities can appear anywhere in a stack.

    • Whether a new instance of the class will be launched to handle a new intent. For the default "standard" mode, a new instance is created to respond to every new intent. Each instance handles just one intent. For the "singleTop" mode, an existing instance of the class is re-used to handle a new intent if it resides at the top of the activity stack of the target task. If it does not reside at the top, it is not re-used. Instead, a new instance is created for the new intent and pushed on the stack.

      For example, suppose a task's activity stack consists of root activity A with activities B, C, and D on top in that order, so the stack is A-B-C-D. An intent arrives for an activity of type D. If D has the default "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 "singleTop", the existing instance is expected to handle the new intent (since it's at the top of the stack) and the stack remains A-B-C-D.

      If, on the other hand, the arriving intent is for an activity of type B, a new instance of B would be launched no matter whether B's mode is "standard" or "singleTop" (since B is not at the top of the stack), so the resulting stack would be A-B-C-D-B.

      As noted above, there's never more than one instance of a "singleTask" or "singleInstance" activity, so that instance is expected to handle all new intents. A "singleInstance" activity is always at the top of the stack (since it is the only activity in the task), so it is always in position to handle the intent. However, a "singleTask" activity may or may not have other activities above it in the stack. If it does, it is not in position to handle the intent, and the intent is dropped. (Even though the intent is dropped, its arrival would have caused the task to come to the foreground, where it would remain.)

    When an existing activity is asked to handle a new intent, the Intent object is passed to the activity in an onNewIntent() call. (The intent object that originally started the activity can be retrieved by calling getIntent().)

    Note that when a new instance of an Activity is created to handle a new intent, the user can always press the BACK key to return to the previous state (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 what that instance was doing before the new intent arrived.

    For more on launch modes, see the description of the <activity> element.

    Clearing the stack

    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, it's as the user left it, except that only the initial activity is present. The idea is that, after a time, users will likely have abandoned what they were doing before and are returning to the task to begin something new.

    That's the default. There are some activity attributes that can be used to control this behavior and modify it:

    The alwaysRetainTaskState attribute
    If this attribute is set to " 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.
    The clearTaskOnLaunch attribute
    If this attribute is set to " 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 polar opposite of alwaysRetainTaskState. The user always returns to the task in its initial state, even after a momentary absence.
    The finishOnTaskLaunch attribute
    This attribute is like clearTaskOnLaunch, but it operates on a single activity, not an entire task. And it can cause any activity to go away, including the root activity. When it's set to " true", the activity remains part of the task only for the current session. If the user leaves and then returns to the task, it no longer is present.

    There's another way to force activities to be removed from the stack. If an Intent object includes the FLAG_ACTIVITY_CLEAR_TOP flag, and the target task already has an instance of the type of activity that should handle the intent in its stack, all activities above that instance are cleared away so that it stands at the top of the stack and can respond to the intent. If the launch mode of the designated activity is "standard", it too will be removed from the stack, and a new instance will be launched to handle the incoming intent. That's because a new instance is always created for a new intent when the launch mode is "standard".

    FLAG_ACTIVITY_CLEAR_TOP is most often used in conjunction with 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.

    Starting tasks

    An activity is set up as the entry point for a task by giving it an intent filter with "android.intent.action.MAIN" as the specified action and "android.intent.category.LAUNCHER" as the specified category. (There's an example of this type of filter in the earlier Intent Filters section.) A filter of this kind causes an icon and label for the activity to be displayed in the application launcher, giving users a way both to launch the task and to return to it at any time after it has been launched.

    This second ability is important: Users must be able to leave a task and then come back to it later. For this reason, the two launch modes that mark activities as always initiating a task, "singleTask" and "singleInstance", should be used only when the activity has a MAIN and LAUNCHER filter. Imagine, for example, what could happen if the filter is missing: An intent launches a "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 ordered behind and obscured by the home screen. And, because it is not represented in the application launcher, the user has no way to return to it.

    A similar difficulty attends the FLAG_ACTIVITY_NEW_TASK flag. 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 it again. Some entities (such as the notification manager) always start activities in an external task, never as part of their own, so they always put FLAG_ACTIVITY_NEW_TASK in the intents they pass to 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.

    For those cases where you don't want the user to be able to return to an activity, set the <activity> element's finishOnTaskLaunch to "true". See Clearing the stack, earlier.

    Processes and Threads

    When the first of an application's components needs to be run, Android starts a Linux process for it with a single thread of execution. By default, all components of the application run in that process and thread.

    However, you can arrange for components to run in other processes, and you can spawn additional threads for any process.

    Processes

    The process where a component runs is controlled by the manifest file. The component elements — <activity>, <service>, <receiver>, and <provider> — each have a process attribute that can specify a process where that component should run. These attributes can be set so that each component runs in its own process, or so that some components share a process while others do not. They can also be set so that components of different applications run in the same process — provided that the applications share the same Linux user ID and are signed by the same authorities. The <application> element also has a process attribute, for setting a default value that applies to all components.

    All components are instantiated in the main thread of the specified process, and system calls to the component are dispatched from that thread. Separate threads are not created for each instance. Consequently, methods that respond to those calls — methods like View.onKeyDown() that report user actions and the lifecycle notifications discussed later in the Component Lifecycles section — always run in the main thread of the process. This means that no component should perform long or blocking operations (such as networking operations or computation loops) when called by the system, since this will block any other components also in the process. You can spawn separate threads for long operations, as discussed under Threads, next.

    Android may decide to shut down a process at some point, when memory is low and required by other processes that are more immediately serving the user. Application components running in the process are consequently destroyed. A process is restarted for those components when there's again work for them to do.

    When deciding which processes to terminate, Android weighs their relative importance to the user. For example, it more readily shuts down a process with activities that are no longer visible on screen than a process with visible activities. The decision whether to terminate a process, therefore, depends on the state of the components running in that process. Those states are the subject of a later section, Component Lifecycles.

    Threads

    Even though you may confine your application to a single process, there will likely be times when you will need to spawn a thread to do some background work. Since the user interface must always be quick to respond to user actions, the thread that hosts an activity should not also host time-consuming operations like network downloads. Anything that may not be completed quickly should be assigned to a different thread.

    Threads are created in code using standard Java Thread objects. Android provides a number of convenience classes for managing threads — Looper for running a message loop within a thread, Handler for processing messages, and HandlerThread for setting up a thread with a message loop.

    Remote procedure calls

    Android has a lightweight mechanism for remote procedure calls (RPCs) — where a method is called locally, but executed remotely (in another process), with any result returned back to the caller. This entails decomposing the method call and all its attendant data to a level the operating system can understand, transmitting it from the local process and address space to the remote process and address space, and reassembling and reenacting the call there. Return values have to be transmitted in the opposite direction. Android provides all the code to do that work, so that you can concentrate on defining and implementing the RPC interface itself.

    An RPC interface can include only methods. All methods are executed synchronously (the local method blocks until the remote method finishes), even if there is no return value.

    In brief, the mechanism works as follows: You'd begin by declaring the RPC interface you want to implement using a simple IDL (interface definition language). From that declaration, the aidl tool generates a Java interface definition that must be made available to both the local and the remote process. It contains two inner class, as shown in the following diagram:

    RPC mechanism.

    The inner classes have all the code needed to administer remote procedure calls for the interface you declared with the IDL. Both inner classes implement the IBinder interface. One of them is used locally and internally by the system; the code you write can ignore it. The other, called Stub, extends the Binder class. In addition to internal code for effectuating the IPC calls, it contains declarations for the methods in the RPC interface you declared. You would subclass Stub to implement those methods, as indicated in the diagram.

    Typically, the remote process would be managed by a service (because a service can inform the system about the process and its connections to other processes). It would have both the interface file generated by the aidl tool and the Stub subclass implementing the RPC methods. Clients of the service would have only the interface file generated by the aidl tool.

    Here's how a connection between a service and its clients is set up:

    • Clients of the service (on the local side) would implement onServiceConnected() and onServiceDisconnected() methods so they can be notified when a successful connection to the remote service is established, and when it goes away. They would then call bindService() to set up the connection.
    • The service's onBind() method would be implemented to either accept or reject the connection, depending on the intent it receives (the intent passed to bindService()). If the connection is accepted, it returns an instance of the Stub subclass.
    • If the service accepts the connection, Android calls the client's onServiceConnected() method and passes it an IBinder object, a proxy for the Stub subclass managed by the service. Through the proxy, the client can make calls on the remote service.

    This brief description omits some details of the RPC mechanism. For more information, see Designing a Remote Interface Using AIDL and the IBinder class description.

    Thread-safe methods

    In a few contexts, the methods you implement may be called from more than one thread, and therefore must be written to be thread-safe.

    This is primarily true for methods that can be called remotely — as in the RPC mechanism discussed in the previous section. When a call on a method implemented in an IBinder object originates in the same process as the IBinder, the method is executed in the caller's thread. However, when the call originates in another process, the method is executed in a thread chosen from a pool of threads that Android maintains in the same process as the IBinder; it's not executed in the main thread of the process. For example, whereas a service's onBind() method would be called from the main thread of the service's process, methods implemented in the object that onBind() returns (for example, a Stub subclass that implements RPC methods) would be called from threads in the pool. Since services can have more than one client, more than one pool thread can engage the same IBinder method at the same time. IBinder methods must, therefore, be implemented to be thread-safe.

    Similarly, a content provider can receive data requests that originate in other processes. Although the ContentResolver and ContentProvider classes hide the details of how the interprocess communication is managed, ContentProvider methods that respond to those requests — the methods query(), insert(), delete(), update(), and getType() — are called from a pool of threads in the content provider's process, not the main thread of the process. Since these methods may be called from any number of threads at the same time, they too must be implemented to be thread-safe.

    Component Lifecycles

    Application components have a lifecycle — a beginning when Android instantiates them to respond to intents through to an end when the instances are destroyed. In between, they may sometimes be active or inactive,or, in the case of activities, visible to the user or invisible. This section discusses the lifecycles of activities, services, and broadcast receivers — including the states that they can be in during their lifetimes, the methods that notify you of transitions between states, and the effect of those states on the possibility that the process hosting them might be terminated and the instances destroyed.

    Activity lifecycle

    An activity has essentially three states:

    • It is active or running when it is in the foreground of the screen (at the top of the activity stack for the current task). This is the activity that is the focus for the user's actions.
    • It is paused if it has lost focus but is still visible to the user. That is, another activity lies on top of it and that activity either is transparent or doesn't cover the full screen, so some of the paused activity can show through. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations.

    • It is stopped if it is completely obscured by another activity. It still retains all state and member information. However, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.

    If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state.

    As an activity transitions from state to state, it is notified of the change by calls to the following protected methods:

    void onCreate(Bundle savedInstanceState)
    void onStart()
    void onRestart()
    void onResume()
    void onPause()
    void onStop()
    void onDestroy()

    All of these methods are hooks that you can override to do appropriate work when the state changes. All activities must implement onCreate() to do the initial setup when the object is first instantiated. Many will also implement onPause() to commit data changes and otherwise prepare to stop interacting with the user.

    Taken together, these seven methods define the entire lifecycle of an activity. There are three nested loops that you can monitor by implementing them:

    • The entire lifetime of an activity happens between the first call to onCreate() through to a single final call to onDestroy(). An activity does all its initial setup of "global" state in onCreate(), and releases all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().
    • The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time, the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods, you can maintain resources that are needed to show the activity to the user. For example, you can register a BroadcastReceiver in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user can no longer see what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity alternates between being visible and hidden to the user.

    • The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time, the activity is in front of all other activities on screen and is interacting with the user. An activity can frequently transition between the resumed and paused states — for example, onPause() is called when the device goes to sleep or when a new activity is started, onResume() is called when an activity result or a new intent is delivered. Therefore, the code in these two methods should be fairly lightweight.

    The following diagram illustrates these loops and the paths an activity may take between states. The colored ovals are major states the activity can be in. The square rectangles represent the callback methods you can implement to perform operations when the activity transitions between states.

     

    State diagram for an Android activity lifecycle.

    The following table describes each of these methods in more detail and locates it within the activity's overall lifecycle:

    MethodDescriptionKillable?Next
    onCreate()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 Saving Activity State, later).

    Always followed by onStart().

    NoonStart()
        onRestart()Called after the activity has been stopped, just prior to it being started again.

    Always followed by onStart()

    NoonStart()
    onStart()Called just before the activity becomes visible to the user.

    Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.

    NoonResume()
    or
    onStop()
        onResume()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.

    Always followed by onPause().

    NoonPause()
    onPause()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.

    Followed either by onResume() if the activity returns back to the front, or by onStop() if it becomes invisible to the user.

    YesonResume()
    or
    onStop()
    onStop()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.

    Followed either by onRestart() if the activity is coming back to interact with the user, or by onDestroy() if this activity is going away.

    YesonRestart()
    or
    onDestroy()
    onDestroy()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 finish() 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 isFinishing() method.Yesnothing

    Note the Killable column in the table above. It indicates whether or not the system can kill the process hosting the activity at any time after the method returns, without executing another line of the activity's code. Three methods (onPause(), onStop(), and onDestroy()) are marked "Yes." Because onPause() is the first of the three, it's the only one that's guaranteed to be called before the process is killed — onStop() and onDestroy() may not be. Therefore, you should use onPause() to write any persistent data (such as user edits) to storage.

    Methods that are marked "No" in the Killable column protect the process hosting the activity from being killed from the moment they are called. Thus an activity is in a killable state, for example, from the time onPause() returns to the time onResume() is called. It will not again be killable until onPause() again returns.

    As noted in a later section, Processes and lifecycle, an activity that's not technically "killable" by this definition might still be killed by the system — but that would happen only in extreme and dire circumstances when there is no other recourse.

    Saving activity state

    When the system, rather than the user, shuts down an activity to conserve memory, the user may expect to return to the activity and find it in its previous state.

    To capture that state before the activity is killed, you can implement an onSaveInstanceState() method for the activity. Android calls this method before making the activity vulnerable to being destroyed — that is, before onPause() is called. It passes the method a Bundle object where you can record the dynamic state of the activity as name-value pairs. When the activity is again started, the Bundle is passed both to onCreate() and to a method that's called after onStart(), onRestoreInstanceState(), so that either or both of them can recreate the captured state.

    Unlike onPause() and the other methods discussed earlier, onSaveInstanceState() and onRestoreInstanceState() are not lifecycle methods. They are not always called. For example, Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key). In that case, the user won't expect to return to the activity, so there's no reason to save its state.

    Because onSaveInstanceState() is not always called, you should use it only to record the transient state of the activity, not to store persistent data. Use onPause() for that purpose instead.

    Coordinating activities

    When one activity starts another, they both experience lifecycle transitions. One pauses and may stop, while the other starts up. On occasion, you may need to coordinate these activities, one with the other.

    The order of lifecycle callbacks is well defined, particularly when the two activities are in the same process:

    1. The current activity's onPause() method is called.
    2. Next, the starting activity's onCreate(), onStart(), and onResume() methods are called in sequence.
    3. Then, if the starting activity is no longer visible on screen, its onStop() method is called.

    Service lifecycle

    A service can be used in two ways:

    • It can be started and allowed to run until someone stops it or it stops itself. In this mode, it's started by calling Context.startService() and stopped by calling Context.stopService(). It can stop itself by calling Service.stopSelf() or Service.stopSelfResult(). Only one stopService() call is needed to stop the service, no matter how many times startService() was called.
    • It can be operated programmatically using an interface that it defines and exports. Clients establish a connection to the Service object and use that connection to call into the service. The connection is established by calling Context.bindService(), and is closed by calling Context.unbindService(). Multiple clients can bind to the same service. If the service has not already been launched, bindService() can optionally launch it.

    The two modes are not entirely separate. You can bind to a service that was started with startService(). For example, a background music service could be started by calling startService() with an Intent object that identifies the music to play. Only later, possibly when the user wants to exercise some control over the player or get information about the current song, would an activity establish a connection to the service by calling bindService(). In cases like this, stopService() will not actually stop the service until the last binding is closed.

    Like an activity, a service has lifecycle methods that you can implement to monitor changes in its state. But they are fewer than the activity methods — only three — and they are public, not protected:

    void onCreate()
    void onStart(Intent intent)
    void onDestroy()

    By implementing these methods, you can monitor two nested loops of the service's lifecycle:

    • The entire lifetime of a service happens between the time onCreate() is called and the time onDestroy() returns. Like an activity, a service does its initial setup in onCreate(), and releases all remaining resources in onDestroy(). For example, a music playback service could create the thread where the music will be played in onCreate(), and then stop the thread in onDestroy().
    • The active lifetime of a service begins with a call to onStart(). This method is handed the Intent object that was passed to startService(). The music service would open the Intent to discover which music to play, and begin the playback.

      There's no equivalent callback for when the service stops — no onStop() method.

    The onCreate() and onDestroy() methods are called for all services, whether they're started by Context.startService() or Context.bindService(). However, onStart() is called only for services started by startService().

    If a service permits others to bind to it, there are additional callback methods for it to implement:

    IBinder onBind(Intent intent)
    boolean onUnbind(Intent intent)
    void onRebind(Intent intent)

    The onBind() callback is passed the Intent object that was passed to bindService and onUnbind() is handed the intent that was passed to unbindService(). If the service permits the binding, onBind() returns the communications channel that clients use to interact with the service. The onUnbind() method can ask for onRebind() to be called if a new client connects to the service.

    The following diagram illustrates the callback methods for a service. Although, it separates services that are created via startService from those created by bindService(), keep in mind that any service, no matter how it's started, can potentially allow clients to bind to it, so any service may receive onBind() and onUnbind() calls.

    State diagram for Service callbacks.

    Broadcast receiver lifecycle

    A broadcast receiver has single callback method:

    void onReceive(Context curContext, Intent broadcastMsg)

    When a broadcast message arrives for the receiver, Android calls its onReceive() method and passes it the Intent object containing the message. The broadcast receiver is considered to be active only while it is executing this method. When onReceive() returns, it is inactive.

    A process with an active broadcast receiver is protected from being killed. But a process with only inactive components can be killed by the system at any time, when the memory it consumes is needed by other processes.

    This presents a problem when the response to a broadcast message is time consuming and, therefore, something that should be done in a separate thread, away from the main thread where other components of the user interface run. If onReceive() spawns the thread and then returns, the entire process, including the new thread, is judged to be inactive (unless other application components are active in the process), putting it in jeopardy of being killed. The solution to this problem is for onReceive() to start a service and let the service do the job, so the system knows that there is still active work being done in the process.

    The next section has more on the vulnerability of processes to being killed.

    Processes and lifecycles

    The Android system tries to maintain an application process for as long as possible, but eventually it will need to remove old processes when memory runs low. To determine which processes to keep and which to kill, Android places each process into an "importance hierarchy" based on the components running in it and the state of those components. Processes with the lowest importance are eliminated first, then those with the next lowest, and so on. There are five levels in the hierarchy. The following list presents them in order of importance:

    1. A foreground process is one that is required for what the user is currently doing. A process is considered to be in the foreground if any of the following conditions hold:
      • It is running an activity that the user is interacting with (the Activity object's onResume() method has been called).
      • It hosts a service that's bound to the activity that the user is interacting with.

      • It has a Service object that's executing one of its lifecycle callbacks (onCreate(), onStart(), or onDestroy()).

      • It has a BroadcastReceiver object that's executing its onReceive() method.

      Only a few foreground processes will exist at any given time. They are killed only as a last resort — if memory is so low that they cannot all continue to run. Generally, at that point, the device has reached a memory paging state, so killing some foreground processes is required to keep the user interface responsive.

    2. A visible process is one that doesn't have any foreground components, but still can affect what the user sees on screen. A process is considered to be visible if either of the following conditions holds:

      • It hosts an activity that is not in the foreground, but is still visible to the user (its onPause() method has been called). This may occur, for example, if the foreground activity is a dialog that allows the previous activity to be seen behind it.
      • It hosts a service that's bound to a visible activity.

      A visible process is considered extremely important and will not be killed unless doing so is required to keep all foreground processes running.

    3. A service process is one that is running a service that has been started with the startService() method and that does not fall into either of the two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing an mp3 in the background or downloading data on the network), so the system keeps them running unless there's not enough memory to retain them along with all foreground and visible processes.

    4. A background process is one holding an activity that's not currently visible to the user (the Activity object's onStop() method has been called). These processes have no direct impact on the user experience, and can be killed at any time to reclaim memory for a foreground, visible, or service process. Usually there are many background processes running, so they are kept in an LRU (least recently used) list to ensure that the process with the activity that was most recently seen by the user is the last to be killed. If an activity implements its lifecycle methods correctly, and captures its current state, killing its process will not have a deleterious effect on the user experience.

    5. An empty process is one that doesn't hold any active application components. The only reason to keep such a process around is as a cache to improve startup time the next time a component needs to run in it. The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.

    Android ranks a process at the highest level it can, based upon the importance of the components currently active in the process. For example, if a process hosts a service and a visible activity, the process will be ranked as a visible process, not a service process.

    In addition, a process's ranking may be increased because other processes are dependent on it. A process that is serving another process can never be ranked lower than the process it is serving. For example, if a content provider in process A is serving a client in process B, or if a service in process A is bound to a component in process B, process A will always be considered at least as important as process B.

    Because a process running a service is ranked higher than one with background activities, an activity that initiates a long-running operation might do well to start a service for that operation, rather than simply spawn a thread — particularly if the operation will likely outlast the activity. Examples of this are playing music in the background and uploading a picture taken by the camera to a web site. Using a service guarantees that the operation will have at least "service process" priority, regardless of what happens to the activity. As noted in the Broadcast receiver lifecycle section earlier, this is the same reason that broadcast receivers should employ services rather than simply put time-consuming operations in a thread.

     

     

    User Interface

    In an Android application, the user interface is built using View and ViewGroup objects. There are many types of views and view groups, each of which is a descendant of the View class.

    View objects are the basic units of user interface expression on the Android platform. The View class serves as the base for subclasses called "widgets," which offer fully implemented UI objects, like text fields and buttons. The ViewGroup class serves as the base for subclasses called "layouts," which offer different kinds of layout architecture, like linear, tabular and relative.

    A View object is a data structure whose properties store the layout parameters and content for a specific rectangular area of the screen. A View object handles its own measurement, layout, drawing, focus change, scrolling, and key/gesture interactions for the rectangular area of the screen in which it resides. As an object in the user interface, a View is also a point of interaction for the user and the receiver of the interaction events.

    View Hierarchy

    On the Android platform, you define an Activity's UI using a hierarchy of View and ViewGroup nodes, as shown in the diagram below. This hierarchy tree can be as simple or complex as you need it to be, and you can build it up using Android's set of predefined widgets and layouts, or with custom Views that you create yourself.

    In order to attach the view hierarchy tree to the screen for rendering, your Activity must call the setContentView() method and pass a reference to the root node object. The Android system receives this reference and uses it to invalidate, measure, and draw the tree. The root node of the hierarchy requests that its child nodes draw themselves — in turn, each view group node is responsible for calling upon each of its own child views to draw themselves. The children may request a size and location within the parent, but the parent object has the final decision on where how big each child can be. Android parses the elements of your layout in-order (from the top of the hierarchy tree), instantiating the Views and adding them to their parent(s). Because these are drawn in-order, if there are elements that overlap positions, the last one to be drawn will lie on top of others previously drawn to that space.

    For a more detailed discussion on how view hierarchies are measured and drawn, read How Android Draws Views.

    Layout

    The most common way to define your layout and express the view hierarchy is with an XML layout file. XML offers a human-readable structure for the layout, much like HTML. Each element in XML is either a View or ViewGroup object (or descendent thereof). View objects are leaves in the tree, ViewGroup objects are branches in the tree (see the View Hierarchy figure above).

    The name of an XML element is respective to the Java class that it represents. So a <TextView> element creates a TextView in your UI, and a <LinearLayout> element creates a LinearLayout view group. When you load a layout resource, the Android system initializes these run-time objects, corresponding to the elements in your layout.

    For example, a simple vertical layout with a text view and a button looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="fill_parent" 
                  android:layout_height="fill_parent"
                  android:orientation="vertical" >
        <TextView android:id="@+id/text"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="Hello, I am a TextView" />
        <Button android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello, I am a Button" />
    </LinearLayout>
    

    Notice that the LinearLayout element contains both the TextView and the Button. You can nest another LinearLayout (or other type of view group) inside here, to lengthen the view hierarchy and create a more complex layout.

    For more on building a UI layout, read Declaring Layout.

    There are a variety of ways in which you can layout your views. Using more and different kinds of view groups, you can structure child views and view groups in an infinite number of ways. Some pre-defined view groups offered by Android (called layouts) include LinearLayout, RelativeLayout, TableLayout, GridLayout and others. Each offers a unique set of layout parameters that are used to define the positions of child views and layout structure.

    To learn about some of the different kinds of view groups used for a layout, read Common Layout Objects.

    Widgets

    A widget is a View object that serves as an interface for interaction with the user. Android provides a set of fully implemented widgets, like buttons, checkboxes, and text-entry fields, so you can quickly build your UI. Some widgets provided by Android are more complex, like a date picker, a clock, and zoom controls. But you're not limited to the kinds of widgets provided by the Android platform. If you'd like to do something more customized and create your own actionable elements, you can, by defining your own View object or by extending and combining existing widgets.

    Read more in Building Custom Components.

    For a list of the widgets provided by Android, see the android.widget package.

    UI Events

    Once you've added some Views/widgets to the UI, you probably want to know about the user's interaction with them, so you can perform actions. To be informed of UI events, you need to do one of two things:

    • Define an event listener and register it with the View. More often than not, this is how you'll listen for events. The View class contains a collection of nested interfaces named On<something>Listener, each with a callback method called On<something>(). For example, View.OnClickListener (for handling "clicks" on a View), View.OnTouchListener (for handling touch screen events in a View), and View.OnKeyListener (for handling device key presses within a View). So if you want your View to be notified when it is "clicked" (such as when a button is selected), implement OnClickListener and define its onClick() callback method (where you perform the action upon click), and register it to the View with setOnClickListener().
    • Override an existing callback method for the View. This is what you should do when you've implemented your own View class and want to listen for specific events that occur within it. Example events you can handle include when the screen is touched (onTouchEvent()), when the trackball is moved (onTrackballEvent()), or when a key on the device is pressed (onKeyDown()). This allows you to define the default behavior for each event inside your custom View and determine whether the event should be passed on to some other child View. Again, these are callbacks to the View class, so your only chance to define them is when you build a custom component.

    Continue reading about handling user interaction with Views in the Handling UI Events document.

    Application menus are another important part of an application's UI. Menus offers a reliable interface that reveals application functions and settings. The most common application menu is revealed by pressing the MENU key on the device. However, you can also add Context Menus, which may be revealed when the user presses and holds down on an item.

    Menus are also structured using a View hierarchy, but you don't define this structure yourself. Instead, you define the onCreateOptionsMenu() or onCreateContextMenu() callback methods for your Activity and declare the items that you want to include in your menu. At the appropriate time, Android will automatically create the necessary View hierarchy for the menu and draw each of your menu items in it.

    Menus also handle their own events, so there's no need to register event listeners on the items in your menu. When an item in your menu is selected, the onOptionsItemSelected() or onContextItemSelected() method will be called by the framework.

    And just like your application layout, you have the option to declare the items for you menu in an XML file.

    Read Creating Menus to learn more.

    Advanced Topics

    Once you've grappled the fundamentals of creating a user interface, you can explore some advanced features for creating a more complex application interface.

    Adapters

    Sometimes you'll want to populate a view group with some information that can't be hard-coded, instead, you want to bind your view to an external source of data. To do this, you use an AdapterView as your view group and each child View is initialized and populated with data from the Adapter.

    The AdapterView object is an implementation of ViewGroup that determines its child views based on a given Adapter object. The Adapter acts like a courier between your data source (perhaps an array of external strings) and the AdapterView, which displays it. There are several implementations of the Adapter class, for specific tasks, such as the CursorAdapter for reading database data from a Cursor, or an ArrayAdapter for reading from an arbitrary array.

    To learn more about using an Adapter to populate your views, read Binding to Data with AdapterView.

    Styles and Themes

    Perhaps you're not satisfied with the look of the standard widgets. To revise them, you can create some of your own styles and themes.

    • A style is a set of one or more formatting attributes that you can apply as a unit to individual elements in your layout. For example, you could define a style that specifies a certain text size and color, then apply it to only specific View elements.
    • A theme is a set of one or more formatting attributes that you can apply as a unit to all activities in an application, or just a single activity. For example, you could define a theme that sets specific colors for the window frame and the panel background, and sets text sizes and colors for menus. This theme can then be applied to specific activities or the entire application.

    Styles and themes are resources. Android provides some default style and theme resources that you can use, or you can declare your own custom style and theme resources.

    Learn more about using styles and themes in the Applying Styles and Themes document.

    Declaring Layout

    Your layout is the architecture for the user interface in an Activity. It defines the layout structure and holds all the elements that appear to the user. You can declare your layout in two ways:

    • Declare UI elements in XML. Android provides a straightforward XML vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts.
    • Instantiate layout elements at runtime. Your application can create View and ViewGroup objects (and manipulate their properties) programmatically.

    The Android framework gives you the flexibility to use either or both of these methods for declaring and managing your application's UI. For example, you could declare your application's default layouts in XML, including the screen elements that will appear in them and their properties. You could then add code in your application that would modify the state of the screen objects, including those declared in XML, at run time.

    The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior. Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations, different device screen sizes, and different languages. Additionally, declaring the layout in XML makes it easier to visualize the structure of your UI, so it's easier to debug problems. As such, this document focuses on teaching you how to declare your layout in XML. If you're interested in instantiating View objects at runtime, refer to the ViewGroup and View class references.

    In general, the XML vocabulary for declaring UI elements closely follows the structure and naming of the classes and methods, where element names correspond to class names and attribute names correspond to methods. In fact, the correspondence is often so direct that you can guess what XML attribute corresponds to a class method, or guess what class corresponds to a given xml element. However, note that not all vocabulary is identical. In some cases, there are slight naming differences. For example, the EditText element has a text attribute that corresponds to EditText.setText().

    Tip: Learn more about different layout types in Common Layout Objects. There are also a collection of tutorials on building various layouts in the Hello Views tutorial guide.

    Write the XML

    Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create web pages in HTML — with a series of nested elements.

    Each layout file must contain exactly one root element, which must be a View or ViewGroup object. Once you've defined the root element, you can add additional layout objects or widgets as child elements to gradually build a View hierarchy that defines your layout. For example, here's an XML layout that uses a vertical LinearLayout to hold a TextView and a Button:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="fill_parent" 
                  android:layout_height="fill_parent" 
                  android:orientation="vertical" >
        <TextView android:id="@+id/text"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="Hello, I am a TextView" />
        <Button android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello, I am a Button" />
    </LinearLayout>
    

    After you've declared your layout in XML, save the file with the .xml extension, in your Android project's res/layout/ directory, so it will properly compile.

    We'll discuss each of the attributes shown here a little later.

    Load the XML Resource

    When you compile your application, each XML layout file is compiled into a View resource. You should load the layout resource from your application code, in your Activity.onCreate() callback implementation. Do so by calling setContentView(), passing it the reference to your layout resource in the form of: R.layout.layout_file_name For example, if your XML layout is saved as main_layout.xml, you would load it for your Activity like so:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView.(R.layout.main_layout);
    }
    

    The onCreate() callback method in your Activity is called by the Android framework when your Activity is launched (see the discussion on Lifecycles, in the Application Fundamantals, for more on this).

    Attributes

    Every View and ViewGroup object supports their own variety of XML attributes. Some attributes are specific to a View object (for example, TextView supports the textSize attribute), but these attributes are also inherited by any View objects that may extend this class. Some are common to all View objects, because they are inherited from the root View class (like the id attribute). And, other attributes are considered "layout parameters," which are attributes that describe certain layout orientations of the View object, as defined by that object's parent ViewGroup object.

    ID

    Any View object may have an integer ID associated with it, to uniquely identify the View within the tree. When the application is compiled, this ID is referenced as an integer, but the ID is typically assigned in the layout XML file as a string, in the id attribute. This is an XML attribute common to all View objects (defined by the View class) and you will use it very often. The syntax for an ID, inside an XML tag is:

    android:id="@+id/my_button"

    The at-symbol (@) at the beginning of the string indicates that the XML parser should parse and expand the rest of the ID string and identify it as an ID resource. The plus-symbol (+) means that this is a new resource name that must be created and added to our resources (in the R.java file). There are a number of other ID resources that are offered by the Android framework. When referencing an Android resource ID, you do not need the plus-symbol, but must add the android package namespace, like so:

    android:id="@android:id/empty"

    With the android package namespace in place, we're now referencing an ID from the android.R resources class, rather than the local resources class.

    In order to create views and reference them from the application, a common pattern is to:

    1. Define a view/widget in the layout file and assign it a unique ID:
      <Button android:id="@+id/my_button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/my_button_text"/>
      
    2. Then create an instance of the view object and capture it from the layout (typically in the onCreate() method):
      Button myButton = (Button) findViewById(R.id.my_button);
      

    Defining IDs for view objects is important when creating a RelativeLayout. In a relative layout, sibling views can define their layout relative to another sibling view, which is referenced by the unique ID.

    An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are searching (which may often be the entire tree, so it's best to be completely unique when possible).

    Layout Parameters

    XML layout attributes named layout_something define layout parameters for the View that are appropriate for the ViewGroup in which it resides.

    Every ViewGroup class implements a nested class that extends 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 view group defines layout parameters for each child view (including the child view group).

    Note that every LayoutParams subclass has its own syntax for setting values. Each child element must define LayoutParams that are appropriate for its parent, though it may also define different LayoutParams for its own children.

    All view groups include a width and height (layout_width and layout_height), and each view is required to define them. Many LayoutParams also include optional margins and borders. You can specify width and height with exact measurements, though you probably won't want to do this often. More often, you will tell your view to size itself either to the dimensions required by its content, or to become as big as its parent view group will allow (with the wrap_content and fill_parent values, respectively). The accepted measurement types are defined in the Available Resources document.

    Layout Position

    The geometry of a view is that of a rectangle. A view has a location, expressed as a pair of left and top coordinates, and two dimensions, expressed as a width and a height. The unit for location and dimensions is the pixel.

    It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate of the rectangle representing the view. These methods both return the location of the view relative to its parent. For instance, when getLeft() returns 20, that means the view is located 20 pixels to the right of the left edge of its direct parent.

    In addition, several convenience methods are offered to avoid unnecessary computations, namely getRight() and getBottom(). These methods return the coordinates of the right and bottom edges of the rectangle representing the view. For instance, calling getRight() is similar to the following computation: getLeft() + getWidth().

    Size, Padding and Margins

    The size of a view is expressed with a width and a height. A view actually possess two pairs of width and height values.

    The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent. The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight().

    The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight().

    To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific amount of pixels. For instance, a left padding of 2 will push the view's content by 2 pixels to the right of the left edge. Padding can be set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight() and getPaddingBottom().

    Even though a view can define a padding, it does not provide any support for margins. However, view groups provide such a support. Refer to ViewGroup and ViewGroup.MarginLayoutParams for further information.

    For more information about dimensions, see Dimension Values.

    ↑ Go to top

    ← Back to User Interface

     

    Creating Menus

    Menus are an important part of any application. They provide familiar interfaces that reveal application functions and settings. Android offers an easy programming interface for developers to provide standardized application menus for various situations.

    Android offers three fundamental types of application menus:

    Options Menu
    This is the primary set of menu items for an Activity. It is revealed by pressing the device MENU key. Within the Options Menu are two groups of menu items:
    Icon Menu
    This is the collection of items initially 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 do not support checkboxes or radio buttons.
    Expanded Menu
    This is a vertical list of items exposed by the "More" menu item from the Icon Menu. It exists only when the Icon Menu becomes over-loaded and is comprised of the sixth Option Menu item and the rest.
    Context Menu
    This is a floating list of menu items that may appear when you perform a long-press on a View (such as a list item).
    Submenu
    This is a floating list of menu items that is revealed by an item in the Options Menu or a Context Menu. A Submenu item cannot support nested Submenus.

    Options Menu

    The Options Menu is opened by pressing the device MENU key. When opened, the Icon Menu is displayed, which holds the first six menu items. If more than six items are added to the Options Menu, then those that can't fit in the Icon Menu are revealed in the Expanded Menu, via the "More" menu item. The Expanded Menu is automatically added when there are more than six items.

    The Options Menu is where you should include basic application functions and any necessary navigation items (e.g., to a home screen or application settings). You can also add Submenus for organizing topics and including extra menu functionality.

    When this menu is opened for the first time, the Android system will call the Activity onCreateOptionsMenu() callback method. Override this method in your Activity and populate the Menu object given to you. You can populate the menu by inflating a menu resource that was defined in XML, or by calling add() for each item you'd like in the menu. This method adds a MenuItem, and returns the newly created object to you. You can use the returned MenuItem to set additional properties like an icon, a keyboard shortcut, an intent, and other settings for the item.

    There are multiple add() methods. Usually, you'll want to use one that accepts an itemId argument. This is a unique integer that allows you to identify the item during a callback.

    When a menu item is selected from the Options Menu, you will recieve a callback to the onOptionsItemSelected() method of your Activity. This callback passes you the MenuItem that has been selected. You can identify the item by requesting the itemId, with getItemId(), which returns the integer that was assigned with the add() method. Once you identify the menu item, you can take the appropriate action.

    Here's an example of this procedure, inside an Activity, wherein we create an Options Menu and handle item selections:

    /* Creates the menu items */
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, MENU_NEW_GAME, 0, "New Game");
        menu.add(0, MENU_QUIT, 0, "Quit");
        return true;
    }
    
    /* Handles item selections */
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case MENU_NEW_GAME:
            newGame();
            return true;
        case MENU_QUIT:
            quit();
            return true;
        }
        return false;
    }
    

    The add() method used in this sample takes four arguments: groupId, itemId, order, and title. The groupId allows you to associate this menu item with a group of other items (more about Menu groups, below) — in this example, we ignore it. itemId is a unique integer that we give the MenuItem so that can identify it in the next callback. order allows us to define the display order of the item — by default, they are displayed by the order in which we add them. title is, of course, the name that goes on the menu item (this can also be a string resource, and we recommend you do it that way for easier localization).

    Tip: If you have several menu items that can be grouped together with a title, consider organizing them into a Submenu.

    Adding icons

    Icons can also be added to items that appears in the Icon Menu with setIcon(). For example:

    menu.add(0, MENU_QUIT, 0, "Quit")
        .setIcon(R.drawable.menu_quit_icon);

    Modifying the menu

    If you want to sometimes re-write the Options Menu as it is opened, override the onPrepareOptionsMenu() method, which is called each time the menu is opened. This will pass you the Menu object, just like the onCreateOptionsMenu() callback. This is useful if you'd like to add or remove menu options depending on the current state of an application or game.

    Note: When changing items in the menu, it's bad practice to do so based on the currently selected item. Keep in mind that, when in touch mode, there will not be a selected (or focused) item. Instead, you should use a Context Menu for such behaviors, when you want to provide functionality based on a particular item in the UI.

    Context Menu

    The Android context menu is similar, in concept, to the menu revealed with a "right-click" on a PC. When a view is registered to a context menu, performing a "long-press" (press and hold for about two seconds) on the object will reveal a floating menu that provides functions relating to that item. Context menus can be registered to any View object, however, they are most often used for items in a ListView, which helpfully indicates the presence of the context menu by transforming the background color of the ListView item when pressed. (The items in the phone's contact list offer an example of this feature.)

    Note: Context menu items do not support icons or shortcut keys.

    To create a context menu, you must override the Activity's context menu callback methods: onCreateContextMenu() and onContextItemSelected(). Inside the onCreateContextMenu() callback method, you can add menu items using one of the add() methods, or by inflating a menu resource that was defined in XML. Then, register a ContextMenu for the View, with registerForContextMenu().

    For example, here is some code that can be used with the Notepad application to add a context menu for each note in the list:

    public void onCreateContextMenu(ContextMenu menu, View v,
                                    ContextMenuInfo menuInfo) {
      super.onCreateContextMenu(menu, v, menuInfo);
      menu.add(0, EDIT_ID, 0, "Edit");
      menu.add(0, DELETE_ID, 0,  "Delete");
    }
    
    public boolean onContextItemSelected(MenuItem item) {
      AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
      switch (item.getItemId()) {
      case EDIT_ID:
        editNote(info.id);
        return true;
      case DELETE_ID:
        deleteNote(info.id);
        return true;
      default:
        return super.onContextItemSelected(item);
      }
    }
    

    In onCreateContextMenu(), we are given not only the ContextMenu to which we will add MenuItems, but also the View that was selected and a ContextMenuInfo object, which provides additional information about the object that was selected. In this example, nothing special is done in onCreateContextMenu() — just a couple items are added as usual. In the onContextItemSelected() callback, we request the AdapterContextMenuInfo from the MenuItem, which provides information about the currently selected item. All we need from this is the list ID for the selected item, so whether editing a note or deleting it, we find the ID with the AdapterContextMenuInfo.info field of the object. This ID is passed to the editNote() and deleteNote() methods to perfrom the respective action.

    Now, to register this context menu for all the items in a ListView, we pass the entire ListView to the registerForContextMenu(View) method:

    registerForContextMenu(getListView());

    Remember, you can pass any View object to register a context menu. Here, getListView() returns the ListView object used in the Notepad application's ListActivity. As such, each item in the list is registered to this context menu.

    A sub menu can be added within any menu, except another sub menu. These are very useful when your application has a lot of functions that may be organized in topics, like the items in a PC application's menu bar (File, Edit, View, etc.).

    A sub menu is created by adding it to an existing Menu with addSubMenu(). This returns a SubMenu object (an extension of Menu). You can then add additional items to this menu, with the normal routine, using the add() methods. For example:

    public boolean onCreateOptionsMenu(Menu menu) {
      boolean result = super.onCreateOptionsMenu(menu);
    
      SubMenu fileMenu = menu.addSubMenu("File");
      SubMenu editMenu = menu.addSubMenu("Edit");
      fileMenu.add("new");
      fileMenu.add("open");
      fileMenu.add("save");
      editMenu.add("undo");
      editMenu.add("redo");
    
      return result;
    }
    

    Callbacks for items selected in a sub menu are made to the parent menu's callback method. For the example above, selections in the sub menu will be handled by the onOptionsItemSelected() callback.

    You can also add Submenus when you define the parent menu in XML.

    Define Menus in XML

    Just like Android UI layouts, you can define application menus in XML, then inflate them in your menu's onCreate...() callback method. This makes your application code cleaner and separates more interface design into XML, which is easier to visualize.

    To start, create a new folder in your project res/ directory called menu. This is where you should keep all XML files that define your application menus.

    In a menu XML layout, there are three valid elements: <menu>, <group> and <item>. The item and group elements must be children of a menu, but item elements may also be the children of a group, and another menu element may be the child of an item (to create a Submenu). Of course, the root node of any file must be a menu element.

    As an example, we'll define the same menu created in the Options Menu section, above. We start with an XML file named options_menu.xml inside the res/menu/ folder:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/new_game"
              android:title="New Game" />
        <item android:id="@+id/quit"
              android:title="Quit" />
    </menu>
    

    Then, in the onCreateOptionsMenu() method, we inflate this resource using MenuInflater.inflate():

    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);
        return true;
    }
    

    The getMenuInflater() method returns the MenuInflater for our activity's context. We then call inflate(), passing it a pointer to our menu resource and the Menu object given by the callback.

    While this small sample may seem like more effort, compared to creating the menu items in the onCreateOptionsMenu() method, this will save a lot of trouble when dealing with more items and it keeps your application code clean.

    You can define menu groups by wrapping item elements in a group element, and create Submenus by nesting another menu inside an item. Each element also supports all the necessary attributes to control features like shortcut keys, checkboxes, icons, and more. To learn about these attributes and more about the XML syntax, see the Menus topic in the Available Resource Types document.

    Menu Features

    Here are some other features that can be applied to most menu items.

    Menu groups

    When adding new items to a menu, you can optionally include each item in a group. A menu group is a collection of menu items that can share certain traits, like whether they are visible, enabled, or checkable.

    A group is defined by an integer (or a resource id, in XML). A menu item is added to the group when it is added to the menu, using one of the add() methods that accepts a groupId as an argument, such as add(int, int, int, int).

    You can show or hide the entire group with setGroupVisible(); enable or disable the group with setGroupEnabled(); and set whether the items can be checkable with setGroupCheckable().

    Checkable menu items

    Any menu item can be used as an interface for turning options on and off. This can be indicated with a checkbox for stand-alone options, or radio buttons for groups of mutually exlusive options (see the screenshot, to the right).

    Note: Menu items in the Icon Menu cannot display a checkbox or radio button. If you choose to make items in the Icon Menu checkable, then you must personally indicate the state by swapping the icon and/or text each time the state changes between on and off.

    To make a single item checkable, use the setCheckable() method, like so:

    menu.add(0, VIBRATE_SETTING_ID, 0, "Vibrate")
        .setCheckable(true);
    

    This will display a checkbox with the menu item (unless it's in the Icon Menu). When the item is selected, the onOptionsItemSelected() callback is called as usual. It is here that you must set the state of the checkbox. You can query the current state of the item with isChecked() and set the checked state with setChecked(). Here's what this looks like inside the onOptionsItemSelected() callback:

    switch (item.getItemId()) {
    case VIBRATE_SETTING_ID:
      if (item.isChecked()) item.setChecked(false);
      else item.setChecked(true);
      return true;
    ...
    }
    

    To make a group of mutually exclusive radio button items, simply assign the same group ID to each menu item and call setGroupCheckable(). In this case, you don't need to call setCheckable() on each menu items, because the group as a whole is set checkable. Here's an example of two mutually exclusive options in a Submenu:

    SubMenu subMenu = menu.addSubMenu("Color");
    subMenu.add(COLOR_MENU_GROUP, COLOR_RED_ID, 0, "Red");
    subMenu.add(COLOR_MENU_GROUP, COLOR_BLUE_ID, 0, "Blue");
    subMenu.setGroupCheckable(COLOR_MENU_GROUP, true, true);
    

    In the setGroupCheckable() method, the first argument is the group ID that we want to set checkable. The second argument is whether we want the group items to be checkable. The last one is whether we want each item to be exclusively checkable (if we set this false, then all the items will be checkboxes instead of radio buttons). When the group is set to be exclusive (radio buttons), each time a new item is selected, all other are automatically de-selected.

     

    Note: Checkable menu items are intended to be used only on a per-session basis and not saved to the device (e.g., the Map mode setting in the Maps application is not saved — screenshot above). If there are application settings that you would like to save for the user, then you should store the data using Preferences, and manage them with a PreferenceActivity.

    Shortcut keys

    Quick access shortcut keys using letters and/or numbers can be added to menu items with setAlphabeticShortcut(char) (to set char shortcut), setNumericShortcut(int) (to set numeric shortcut), or setShortcut(char,int) (to set both). Case is not sensitive. For example:

    menu.add(0, MENU_QUIT, 0, "Quit")
        .setAlphabeticShortcut('q');
    

    Now, when the menu is open (or while holding the MENU key), pressing the "q" key will select this item.

    This shortcut key will be displayed as a tip in the menu item, below the menu item name (except for items in the Icon Menu).

    Note: Shortcuts cannot be added to items in a Context Menu.

    Menu item intents

    If you've read the Application Fundamentals, then you're at least a little familiar with Android Intents. These allow applications to bind with each other, share information, and perform user tasks cooperatively. Just like your application might fire an Intent to launch a web browser, an email client, or another Activity in your application, you can perform such actions from within a menu. There are two ways to do this: define an Intent and assign it to a single menu item, or define an Intent and allow Android to search the device for activities and dynamically add a menu item for each one that meets the Intent criteria.

    For more information on creating Intents and providing your application's services to other applications, read the Intents and Intent Filters document.

    Set an intent for a single menu item

    If you want to offer a specific menu item that launches a new Activity, then you can specifically define an Intent for the menu item with the setIntent() method.

    For example, inside the onCreateOptionsMenu() method, you can define a new menu item with an Intent like this:

    MenuItem menuItem = menu.add(0, PHOTO_PICKER_ID, 0, "Select Photo");
    menuItem.setIntent(new Intent(this, PhotoPicker.class));
    

    Android will automatically launch the Activity when the item is selected.

    Note: This will not return a result to your Activity. If you wish to be returned a result, then do not use setIntent(). Instead, handle the selection as usual in the onOptionsMenuItemSelected() or onContextMenuItemSelected() callback and call startActivityForResult().

    Dynamically add intents

    If there are potentially multiple activities that are relevant to your current Activity or selected item, then the application can dynamically add menu items that execute other services.

    During menu creation, define an Intent with the category Intent.ALTERNATIVE_CATEGORY and/or Intent.SELECTED_ALTERNATIVE, the MIME type currently selected (if any), and any other requirements, the same way as you would satisfy an intent filter to open a new Activity. Then call addIntentOptions() to have Android search for any services meeting those requirements and add them to the menu for you. If there are no applications installed that satisfy the Intent, then no additional menu items are added.

    Note: SELECTED_ALTERNATIVE is used to handle the currently selected element on the screen. So, it should only be used when creating a Menu in onCreateContextMenu() or onPrepareOptionsMenu(), which is called every time the Options Menu is opened.

    Here's an example demonstrating how an application would search for additional services to display on its menu.

    public boolean onCreateOptionsMenu(Menu menu){
        super.onCreateOptionsMenu(menu);
    
        // Create an Intent that describes the requirements to fulfill, to be included
        // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. 
        Intent intent = new Intent(null, getIntent().getData());
        intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
            
        // Search for, and populate the menu with, acceptable offering applications.
        menu.addIntentOptions(
             thisClass.INTENT_OPTIONS,  // Menu group 
             0,      // Unique item ID (none)
             0,      // Order for the items (none)
             this.getComponentName(),   // The current Activity name
             null,   // Specific items to place first (none)
             intent, // Intent created above that describes our requirements
             0,      // Additional flags to control items (none)
             null);  // Array of MenuItems that corrolate to specific items (none)
    
        return true;
    }

    For each Activity found that provides an Intent Filter matching the Intent defined, a menu item will be added, using the android:label value of the intent filter as the text for the menu item. The addIntentOptions() method will also return the number of menu items added.

    Also be aware that, when addIntentOptions() is called, it will override any and all menu items in the menu group specified in the first argument.

    If you wish to offer the services of your Activity to other application menus, then you only need to define an intent filter as usual. Just be sure to include the ALTERNATIVE and/or SELECTED_ALTERNATIVE values in the name attribute of a <category> element in the intent filter. For example:

    <intent-filter label="Resize Image">
        ...
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        ...
    </intent-filter>
    

    read more about writing intent filters in the Intents and Intent Filters document.

    For a sample application using this technique, see the Note Pad sample code.

    ↑ Go to top

    ← Back to User Interface

    Creating Dialogs

    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.

    The Android API supports the following types of Dialog objects:

    AlertDialog
    A dialog that can manage zero, one, two, or three buttons, and/or a list of selectable items that can include checkboxes or radio buttons. The AlertDialog is capable of constructing most dialog user interfaces and is the suggested dialog type. See Creating an AlertDialog below.
    ProgressDialog
    A dialog that displays a progress wheel or progress bar. Because it's an extension of the AlertDialog, it also supports buttons. See Creating a ProgressDialog below.
    DatePickerDialog
    A dialog that allows the user to select a date. See the Hello DatePicker tutorial.
    TimePickerDialog
    A dialog that allows the user to select a time. See the Hello TimePicker tutorial.

    If you would like to customize your own dialog, you can extend the base Dialog object or any of the subclasses listed above and define a new layout. See the section on Creating a Custom Dialog below.

    Showing a Dialog

    A dialog is always created and displayed as a part of an Activity. You should normally create dialogs from within your Activity's onCreateDialog(int) callback method. When you use this callback, the Android system automatically manages the state of each dialog and hooks them to the Activity, effectively making it the "owner" of each dialog. As such, each dialog inherits certain properties from the Activity. For example, when a dialog is open, the Menu key reveals the options menu defined for the Activity and the volume keys modify the audio stream used by the Activity.

    Note: If you decide to create a dialog outside of the onCreateDialog() method, it will not be attached to an Activity. You can, however, attach it to an Activity with setOwnerActivity(Activity).

    When you want to show a dialog, call showDialog(int) and pass it an integer that uniquely identifies the dialog that you want to display.

    When a dialog is requested for the first time, Android calls onCreateDialog(int) from your Activity, which is where you should instantiate the Dialog. This callback method is passed the same ID that you passed to showDialog(int). After you create the Dialog, return the object at the end of the method.

    Before the dialog is displayed, Android also calls the optional callback method onPrepareDialog(int, Dialog). Define this method if you want to change any properties of the dialog each time it is opened. This method is called every time a dialog is opened, whereas onCreateDialog(int) is only called the very first time a dialog is opened. If you don't define onPrepareDialog(), then the dialog will remain the same as it was the previous time it was opened. This method is also passed the dialog's ID, along with the Dialog object you created in onCreateDialog().

    The best way to define the onCreateDialog(int) and onPrepareDialog(int, Dialog) callback methods is with a switch statement that checks the id parameter that's passed into the method. Each case should check for a unique dialog ID and then create and define the respective Dialog. For example, imagine a game that uses two different dialogs: one to indicate that the game has paused and another to indicate that the game is over. First, define an integer ID for each dialog:

    static final int DIALOG_PAUSED_ID = 0;
    static final int DIALOG_GAMEOVER_ID = 1;
    

    Then, define the onCreateDialog(int) callback with a switch case for each ID:

    protected Dialog onCreateDialog(int id) {
        Dialog dialog;
        switch(id) {
        case DIALOG_PAUSED_ID:
            // do the work to define the pause Dialog
            break;
        case DIALOG_GAMEOVER_ID:
            // do the work to define the game over Dialog
            break;
        default:
            dialog = null;
        }
        return dialog;
    }
    

    Note: In this example, there's no code inside the case statements because the procedure for defining your Dialog is outside the scope of this section. See the section below about Creating an AlertDialog, offers code suitable for this example.

    When it's time to show one of the dialogs, call showDialog(int) with the ID of a dialog:

    showDialog(DIALOG_PAUSED_ID);
    

    Dismissing a Dialog

    When you're ready to close your dialog, you can dismiss it by calling dismiss() on the Dialog object. If necessary, you can also call dismissDialog(int) from the Activity, which effectively calls dismiss() on the Dialog for you.

    If you are using onCreateDialog(int) to manage the state of your dialogs (as discussed in the previous section), then every time your dialog is dismissed, the state of the Dialog object is retained by the Activity. If you decide that you will no longer need this object or it's important that the state is cleared, then you should call removeDialog(int). This will remove any internal references to the object and if the dialog is showing, it will dismiss it.

    Using dismiss listeners

    If you'd like your applcation to perform some procedures the moment that a dialog is dismissed, then you should attach an on-dismiss listener to your Dialog.

    First define the DialogInterface.OnDismissListener interface. This interface has just one method, onDismiss(DialogInterface), which will be called when the dialog is dismissed. Then simply pass your OnDismissListener implementation to setOnDismissListener().

    However, note that dialogs can also be "cancelled." This is a special case that indicates the dialog was explicitly cancelled by the user. This will occur if the user presses the "back" button to close the dialog, or if the dialog explicitly calls cancel() (perhaps from a "Cancel" button in the dialog). When a dialog is cancelled, the OnDismissListener will still be notified, but if you'd like to be informed that the dialog was explicitly cancelled (and not dismissed normally), then you should register an DialogInterface.OnCancelListener with setOnCancelListener().

    Creating an AlertDialog

    An AlertDialog is an extension of the Dialog class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. You should use it for dialogs that use any of the following features:

    • A title
    • A text message
    • One, two, or three buttons
    • A list of selectable items (with optional checkboxes or radio buttons)

    To create an AlertDialog, use the AlertDialog.Builder subclass. Get a Builder with AlertDialog.Builder(Context) and then use the class's public methods to define all of the AlertDialog properties. After you're done with the Builder, retrieve the AlertDialog object with create().

    The following topics show how to define various properties of the AlertDialog using the AlertDialog.Builder class. If you use any of the following sample code inside your onCreateDialog() callback method, you can return the resulting Dialog object to display the dialog.

    Adding buttons

    To create an AlertDialog with side-by-side buttons like the one shown in the screenshot to the right, use the set...Button() methods:

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    MyActivity.this.finish();
               }
           })
           .setNegativeButton("No", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
               }
           });
    AlertDialog alert = builder.create();
    

    First, add a message for the dialog with setMessage(CharSequence). Then, begin method-chaining and set the dialog to be not cancelable (so the user cannot close the dialog with the back button) with setCancelable(boolean). For each button, use one of the set...Button() methods, such as setPositiveButton(), that accepts the name for the button and a DialogInterface.OnClickListener that defines the action to take when the user selects the button.

    Note: You can only add one of each button type to the AlertDialog. That is, you cannot have more than one "positive" button. This limits the number of possible buttons to three: positive, neutral, and negative. These names are technically irrelevant to the actual functionality of your buttons, but should help you keep track of which one does what.

    Adding a list

    To create an AlertDialog with a list of selectable items like the one shown to the right, use the setItems() method:

    final CharSequence[] items = {"Red", "Green", "Blue"};
    
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Pick a color");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int item) {
            Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
        }
    });
    AlertDialog alert = builder.create();
    

    First, add a title to the dialog with setTitle(CharSequence). Then, add a list of selectable items with setItems(), which accepts the array of items to display and a DialogInterface.OnClickListener that defines the action to take when the user selects an item.

    Adding checkboxes and radio buttons

    To create a list of multiple-choice items (checkboxes) or single-choice items (radio buttons) inside the dialog, use the setMultiChoiceItems() and setSingleChoiceItems() methods, respectively. If you create one of these selectable lists in the onCreateDialog() callback method, Android manages the state of the list for you. As long as the Activity is active, the dialog remembers the items that were previously selected, but when the user exits the Activity, the selection is lost.

    Note: To save the selection when the user leaves or pauses the Activity, you must properly save and restore the setting throughout the Activity Lifecycle. To permanently save the selections, even when the Activity process is completely shutdown, you need to save the settings with one of the Data Storage techniques.

    To create an AlertDialog with a list of single-choice items like the one shown to the right, use the same code from the previous example, but replace the setItems() method with setSingleChoiceItems():

    final CharSequence[] items = {"Red", "Green", "Blue"};
    
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Pick a color");
    builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int item) {
            Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
        }
    });
    AlertDialog alert = builder.create();
    

    The second parameter in the setSingleChoiceItems() method is an integer value for the checkedItem, which indicates the zero-based list position of the default selected item. Use "-1" to indicate that no item should be selected by default.

    Creating a ProgressDialog

    A ProgressDialog is an extension of the AlertDialog class that can display a progress animation in the form of a spinning wheel, for a task with progress that's undefined, or a progress bar, for a task that has a defined progression. The dialog can also provide buttons, such as one to cancel a download.

    Opening a progress dialog can be as simple as calling ProgressDialog.show(). For example, the progress dialog shown to the right can be easily achieved without managing the dialog through the onCreateDialog(int) callback, as shown here:

    ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", 
                            "Loading. Please wait...", true);
    

    The first parameter is the application Context, the second is a title for the dialog (left empty), the third is the message, and the last parameter is whether the progress is indeterminate (this is only relevant when creating a progress bar, which is discussed in the next section).

    The default style of a progress dialog is the spinning wheel. If you want to create a progress bar that shows the loading progress with granularity, some more code is required, as discussed in the next section.

    Showing a progress bar

    To show the progression with an animated progress bar:

    1. Initialize the ProgressDialog with the class constructor, ProgressDialog(Context).
    2. Set the progress style to "STYLE_HORIZONTAL" with setProgressStyle(int) and set any other properties, such as the message.
    3. When you're ready to show the dialog, call show() or return the ProgressDialog from the onCreateDialog(int) callback.
    4. You can increment the amount of progress displayed in the bar by calling either setProgress(int) with a value for the total percentage completed so far or incrementProgressBy(int) with an incremental value to add to the total percentage completed so far.

    For example, your setup might look like this:

    ProgressDialog progressDialog;
    progressDialog = new ProgressDialog(mContext);
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.setMessage("Loading...");
    progressDialog.setCancelable(false);
    

    The setup is simple. Most of the code needed to create a progress dialog is actually involved in the process that updates it. You might find that it's necessary to create a second thread in your application for this work and then report the progress back to the Activity's UI thread with a Handler object. If you're not familiar with using additional threads with a Handler, see the example Activity below that uses a second thread to increment a progress dialog managed by the Activity.

    <script type="text/javascript"></script>
    Example ProgressDialog with a second thread

    This example uses a second thread to track the progress of a process (which actually just counts up to 100). The thread sends a Message back to the main Activity through a Handler each time progress is made. The main Activity then updates the ProgressDialog.

    package com.example.progressdialog;
    
    import android.app.Activity;
    import android.app.Dialog;
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class NotificationTest extends Activity {
        static final int PROGRESS_DIALOG = 0;
        Button button;
        ProgressThread progressThread;
        ProgressDialog progressDialog;
       
        /** Called when the activity is first created. */
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            // Setup the button that starts the progress dialog
            button = (Button) findViewById(R.id.progressDialog);
            button.setOnClickListener(new OnClickListener(){
                public void onClick(View v) {
                    showDialog(PROGRESS_DIALOG);
                }
            }); 
        }
       
        protected Dialog onCreateDialog(int id) {
            switch(id) {
            case PROGRESS_DIALOG:
                progressDialog = new ProgressDialog(NotificationTest.this);
                progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                progressDialog.setMessage("Loading...");
                progressThread = new ProgressThread(handler);
                progressThread.start();
                return progressDialog;
            default:
                return null;
            }
        }
    
        // 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");
                progressDialog.setProgress(total);
                if (total >= 100){
                    dismissDialog(PROGRESS_DIALOG);
                    progressThread.setState(ProgressThread.STATE_DONE);
                }
            }
        };
    
        /** Nested class that performs progress calculations (counting) */
        private class ProgressThread extends Thread {
            Handler mHandler;
            final static int STATE_DONE = 0;
            final static int STATE_RUNNING = 1;
            int mState;
            int total;
           
            ProgressThread(Handler h) {
                mHandler = h;
            }
           
            public void run() {
                mState = STATE_RUNNING;   
                total = 0;
                while (mState == STATE_RUNNING) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Log.e("ERROR", "Thread Interrupted");
                    }
                    Message msg = mHandler.obtainMessage();
                    Bundle b = new Bundle();
                    b.putInt("total", total);
                    msg.setData(b);
                    mHandler.sendMessage(msg);
                    total++;
                }
            }
            
            /* sets the current state for the thread,
             * used to stop the thread */
            public void setState(int state) {
                mState = state;
            }
        }
    }
    

    Creating a Custom Dialog

    If you want a customized design for a dialog, you can create your own layout for the dialog window with layout and widget elements. After you've defined your layout, pass the root View object or layout resource ID to setContentView(View).

    For example, to create the dialog shown to the right:

    1. Create an XML layout saved as custom_dialog.xml:
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:id="@+id/layout_root"
                    android:orientation="horizontal"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:padding="10dp"
                    >
          <ImageView android:id="@+id/image"
                     android:layout_width="wrap_content"
                     android:layout_height="fill_parent"
                     android:layout_marginRight="10dp"
                     />
          <TextView android:id="@+id/text"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                    android:textColor="#FFF"
                    />
      </LinearLayout>
      

      This XML defines an ImageView and a TextView inside a LinearLayout.

    2. Set the above layout as the dialog's content view and define the content for the ImageView and TextView elements:

       

      Context mContext = getApplicationContext();
      Dialog dialog = new Dialog(mContext);
      
      dialog.setContentView(R.layout.custom_dialog);
      dialog.setTitle("Custom Dialog");
      
      TextView text = (TextView) dialog.findViewById(R.id.text);
      text.setText("Hello, this is a custom dialog!");
      ImageView image = (ImageView) dialog.findViewById(R.id.image);
      image.setImageResource(R.drawable.android);
      

      After you instantiate the Dialog, set your custom layout as the dialog's content view with setContentView(int), passing it the layout resource ID. Now that the Dialog has a defined layout, you can capture View objects from the layout with findViewById(int) and modify their content.

    3. That's it. You can now show the dialog as described in Showing A Dialog.

    A dialog made with the base Dialog class must have a title. If you don't call setTitle(), then the space used for the title remains empty, but still visible. If you don't want a title at all, then you should create your custom dialog using the AlertDialog class. However, because an AlertDialog is created easiest with the AlertDialog.Builder class, you do not have access to the setContentView(int) method used above. Instead, you must use setView(View). This method accepts a View object, so you need to inflate the layout's root View object from XML.

    To inflate the XML layout, retrieve the LayoutInflater with getLayoutInflater() (or getSystemService()), and then call inflate(int, ViewGroup), where the first parameter is the layout resource ID and the second is the ID of the root View. At this point, you can use the inflated layout to find View objects in the layout and define the content for the ImageView and TextView elements. Then instantiate the AlertDialog.Builder and set the inflated layout for the dialog with setView(View).

    Here's an example, creating a custom layout in an AlertDialog:

    AlertDialog.Builder builder;
    AlertDialog alertDialog;
    
    Context mContext = getApplicationContext();
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER);
    View layout = inflater.inflate(R.layout.custom_dialog,
                                   (ViewGroup) findViewById(R.id.layout_root));
    
    TextView text = (TextView) layout.findViewById(R.id.text);
    text.setText("Hello, this is a custom dialog!");
    ImageView image = (ImageView) layout.findViewById(R.id.image);
    image.setImageResource(R.drawable.android);
    
    builder = new AlertDialog.Builder(mContext);
    builder.setView(layout);
    alertDialog = builder.create();
    

    Using an AlertDialog for your custom layout lets you take advantage of built-in AlertDialog features like managed buttons, selectable lists, a title, an icon and so on.

    For more information, refer to the reference documentation for the Dialog and AlertDialog.Builder classes.

    ↑ Go to top

    ← Back to User Interface

     

    Handling UI Events

    On Android, there's more than one way to intercept the events from a user's interaction with your application. When considering events within your user interface, the approach is to capture the events from the specific View object that the user interacts with. The View class provides the means to do so.

    Within the various View classes that you'll use to compose your layout, you may notice several public callback methods that look useful for UI events. These methods are called by the Android framework when the respective action occurs on that object. For instance, when a View (such as a Button) is touched, the onTouchEvent() method is called on that object. However, in order to intercept this, you must extend the class and override the method. Obviously, extending every View object you want to use (just to handle an event) would be obsurd. This is why the View class also contains a collection of nested interfaces with callbacks that you can much more easily define. These interfaces, called event listeners, are your ticket to capturing the user interaction with your UI.

    While you will more commonly use the event listeners to listen for user interaction, there may come a time when you do want to extend a View class, in order to build a custom component. Perhaps you want to extend the Button class to make something more fancy. In this case, you'll be able to define the default event behaviors for your class using the class event handlers.

    Event Listeners

    An event listener is an interface in the View class that contains a single callback method. These methods will be called by the Android framework when the View to which the listener has been registered is triggered by user interaction with the item in the UI.

    Included in the event listener interfaces are the following callback methods:

    onClick()
    From View.OnClickListener. This is called when the user either touches the item (when in touch mode), or focuses upon the item with the navigation-keys or trackball and presses the suitable "enter" key or presses down on the trackball.
    onLongClick()
    From View.OnLongClickListener. This is called when the user either touches and holds the item (when in touch mode), or focuses upon the item with the navigation-keys or trackball and presses and holds the suitable "enter" key or presses and holds down on the trackball (for one second).
    onFocusChange()
    From View.OnFocusChangeListener. This is called when the user navigates onto or away from the item, using the navigation-keys or trackball.
    onKey()
    From View.OnKeyListener. This is called when the user is focused on the item and presses or releases a key on the device.
    onTouch()
    From View.OnTouchListener. This is called when the user performs an action qualified as a touch event, including a press, a release, or any movement gesture on the screen (within the bounds of the item).
    onCreateContextMenu()
    From View.OnCreateContextMenuListener. This is called when a Context Menu is being built (as the result of a sustained "long click"). See the discussion on context menus in Creating Menus for more information.

    These methods are the sole inhabitants of their respective interface. To define one of these methods and handle your events, implement the nested interface in your Activity or define it as an anonymous class. Then, pass an instance of your implementation to the respective View.set...Listener() method. (E.g., call setOnClickListener() and pass it your implementation of the OnClickListener.)

    The example below shows how to register an on-click listener for a Button.

    // Create an anonymous implementation of OnClickListener
    private OnClickListener mCorkyListener = new OnClickListener() {
        public void onClick(View v) {
          // do something when the button is clicked
        }
    };
    
    protected void onCreate(Bundle savedValues) {
        ...
        // Capture our button from layout
        Button button = (Button)findViewById(R.id.corky);
        // Register the onClick listener with the implementation above
        button.setOnClickListener(mCorkyListener);
        ...
    }
    

    You may also find it more conventient to implement OnClickListener as a part of your Activity. This will avoid the extra class load and object allocation. For example:

    public class ExampleActivity extends Activity implements OnClickListener {
        protected void onCreate(Bundle savedValues) {
            ...
            Button button = (Button)findViewById(R.id.corky);
            button.setOnClickListener(this);
        }
    
        // Implement the OnClickListener callback
        public void onClick(View v) {
          // do something when the button is clicked
        }
        ...
    }
    

    Notice that the onClick() callback in the above example has no return value, but some other event listener methods must return a boolean. The reason depends on the event. For the few that do, here's why:

    • onLongClick() - This returns a boolean to indicate whether you have consumed the event and it should not be carried further. That is, return true to indicate that you have handled the event and it should stop here; return false if you have not handled it and/or the event should continue to any other on-click listeners.
    • onKey() - This returns a boolean to indicate whether you have consumed the event and it should not be carried further. That is, return true to indicate that you have handled the event and it should stop here; return false if you have not handled it and/or the event should continue to any other on-key listeners.
    • onTouch() - This returns a boolean to indicate whether your listener consumes this event. The important thing is that this event can have multiple actions that follow each other. So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a fingure gesture, or the eventual up action event.

    Remember that key events are always delivered to the View currently in focus. They are dispatched starting from the top of the View hierarchy, and then down, until they reach the appropriate destination. If your View (or a child of your View) currently has focus, then you can see the event travel through the dispatchKeyEvent() method. As an alternative to capturing key events through your View, you can also receive all of the events inside your Activity with onKeyDown() and onKeyUp().

    Note: Android will call event handlers first and then the appropriate default handlers from the class definition second. As such, returning true from these event listeners will stop the propagation of the event to other event listeners and will also block the callback to the default event handler in the View. So be certain that you want to terminate the event when you return true.

    Event Handlers

    If you're building a custom component from View, then you'll be able to define several callback methods used as default event handlers. In the document on Building Custom Components, you'll learn see some of the common callbacks used for event handling, including:

    There are some other methods that you should be awere of, which are not part of the View class, but can directly impact the way you're able to handle events. So, when managing more complex events inside a layout, consider these other methods:

    Touch Mode

    When a user is navigating a user interface with directional keys or a trackball, it is necessary to give focus to actionable items (like buttons) so the user can see what will accept input. If the device has touch capabilities, however, and the user begins interacting with the interface by touching it, then it is no longer necessary to highlight items, or give focus to a particular View. Thus, there is a mode for interaction named "touch mode."

    For a touch-capable device, once the user touches the screen, the device will enter touch mode. From this point onward, only Views for which isFocusableInTouchMode() is true will be focusable, such as text editing widgets. Other Views that are touchable, like buttons, will not take focus when touched; they will simply fire their on-click listeners when pressed.

    Any time a user hits a directional key or scrolls with a trackball, the device will exit touch mode, and find a view to take focus. Now, the user may resume interacting with the user interface without touching the screen.

    The touch mode state is maintained throughout the entire system (all windows and activities). To query the current state, you can call isInTouchMode() to see whether the device is currently in touch mode.

    Handling Focus

    The framework will handle routine focus movement in response to user input. This includes changing the focus as Views are removed or hidden, or as new Views become available. Views indicate their willingness to take focus through the isFocusable() method. To change whether a View can take focus, call setFocusable(). When in touch mode, you may query whether a View allows focus with isFocusableInTouchMode(). You can change this with setFocusableInTouchMode().

    Focus movement is based on an algorithm which finds the nearest neighbor in a given direction. In rare cases, the default algorithm may not match the intended behavior of the developer. In these situations, you can provide explicit overrides with the following XML attributes in the layout file: nextFocusDown, nextFocusLeft, nextFocusRight, and nextFocusUp. Add one of these attributes to the View from which the focus is leaving. Define the value of the attribute to be the id of the View to which focus should be given. For example:

    <LinearLayout
        android:orientation="vertical"
        ... >
      <Button android:id="@+id/top"
              android:nextFocusUp="@+id/bottom"
              ... />
      <Button android:id="@+id/bottom"
              android:nextFocusDown="@+id/top"
              ... />
    </LinearLayout>
    

    Ordinarily, in this vertical layout, navigating up from the first Button would not go anywhere, nor would navigating down from the second Button. Now that the top Button has defined the bottom one as the nextFocusUp (and vice versa), the navigation focus will cycle from top-to-bottom and bottom-to-top.

    If you'd like to declare a View as focusable in your UI (when it is traditionally not), add the android:focusable XML attribute to the View, in your layout declaration. Set the value true. You can also declare a View as focusable while in Touch Mode with android:focusableInTouchMode.

    To request a particular View to take focus, call requestFocus().

    To listen for focus events (be notified when a View receives or looses focus), use onFocusChange(), as discussed in the Event Listeners section, above.

    ↑ Go to top

    ← Back to User Interface

    Notifying the User

    Several types of situations may arise that require you to notify the user about an event that occurs in your application. Some events require the user to respond and others do not. For example:

    • When an event such as saving a file is complete, a small message should appear to confirm that the save was successful.
    • If the application is running in the background and needs the user's attention, the application should create a notificaiton that allows the user to respond at his or her convenience.
    • If the application is performing work that the user must wait for (such as loading a file), the application should show a hovering progress wheel or bar.

    Each of these notification tasks can be achieved using a different technique:

    This document summarizes each of these techniques for notifying the user and includes links to full documentation.

    Toast Notification

    A toast notificaiton is a message that pops up on the surface of the window. It only fills the amount of space required for the message and the user's current activity remains visible and interactive. The notification automatically fades in and out, and does not accept interaction events. Because a toast can be created from a background Service, it appears even if the application isn't visible.

    A toast is best for short text messages, such as "File saved," when you're fairly certain the user is paying attention to the screen. A toast can not accept user interaction events; if you'd like the user to respond and take action, consider using a Status Bar Notification instead.

    For more information, refer to Creating Toast Notifications.

    Status Bar Notification

    A status bar notification adds an icon to the system's status bar (with an optional ticker-text message) and an expanded message in the "Notifications" window. When the user selects the expanded message, Android fires an Intent that is defined by the notification (usually to launch an Activity). You can also configure the notification to alert the user with a sound, a vibration, and flashing lights on the device.

    This kind of notification is ideal when your application is working in a background Service and needs to notify the user about an event. If you need to alert the user about an event that occurs while your Activity is still in focus, consider using a Dialog Notification instead.

    For more information, refer to Creating Status Bar Notifications.

    Dialog Notification

    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.

    You should use a dialog when you need to show a progress bar or a short message that requires confirmation from the user (such as an alert with "OK" and "Cancel" buttons). You can use also use dialogs as integral componenents in your application's UI and for other purposes besides notifications. For a complete discussion on all the available types of dialogs, including its uses for notifications, refer to Creating Dialogs.

    ↑ Go to top
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值