SlideShare uma empresa Scribd logo
1 de 58
Baixar para ler offline
Services.

A Service is an application component that can perform long-running operations in the background and
does not provide a user interface. Another application component can start a service and it will
continue to run in the background even if the user switches to another application. Additionally, a
component can bind to a service to interact with it and even perform interprocess communication
(IPC). For example, a service might handle network transactions, play music, perform file I/O, or
interact with a content provider, all from the background.

A service can essentially take two forms:

Started

        A service is "started" when an application component (such as an activity) starts it by calling
        startService(). Once started, a service can run in the background indefinitely, even if the
        component that started it is destroyed. Usually, a started service performs a single operation
        and does not return a result to the caller. For example, it might download or upload a file over
        the network. When the operation is done, the service should stop itself.

Bound
        A service is "bound" when an application component binds to it by calling bindService(). A
        bound service offers a client-server interface that allows components to interact with the
        service, send requests, get results, and even do so across processes with interprocess
        communication (IPC). A bound service runs only as long as another application component is
        bound to it. Multiple components can bind to the service at once, but when all of them unbind,
        the service is destroyed.

Although this documentation generally discusses these two types of services separately, your service
can work both ways—it can be started (to run indefinitely) and also allow binding. It's simply a matter
of whether you implement a couple callback methods: onStartCommand() to allow components to start
it and onBind() to allow binding.

Regardless of whether your application is started, bound, or both, any application component can use
the service (even from a separate application), in the same way that any component can use an
activity—by starting it with an Intent. However, you can declare the service as private, in the manifest
file, and block access from other applications. This is discussed more in the section about Declaring
the service in the manifest.

  Caution: A service runs in the main thread of its hosting process—the service does not create its
  own thread and does not run in a separate process (unless you specify otherwise). This means
  that, if your service is going to do any CPU intensive work or blocking operations (such as MP3
  playback or networking), you should create a new thread within the service to do that work. By
  using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and
  the application's main thread can remain dedicated to user interaction with your activities.
The Basics

Should you use a service or a thread?
A service is simply a component that can run in the background even when the user is not interacting
with your application. Thus, you should create a service only if that is what you need.

If you need to perform work outside your main thread, but only while the user is interacting with your
application, then you should probably instead create a new thread and not a service. For example, if
you want to play some music, but only while your activity is running, you might create a thread in
onCreate(), start running it in onStart(), then stop it in onStop(). Also consider using AsyncTask or
HandlerThread, instead of the traditional Thread class. See the Processes and Threading document
for more information about threads.

Remember that if you do use a service, it still runs in your application's main thread by default, so you
should still create a new thread within the service if it performs intensive or blocking operations.

To create a service, you must create a subclass of Service (or one of its existing subclasses). In your
implementation, you need to override some callback methods that handle key aspects of the service
lifecycle and provide a mechanism for components to bind to the service, if appropriate. The most
important callback methods you should override are:

onStartCommand()

       The system calls this method when another component, such as an activity, requests that the
       service be started, by calling startService(). Once this method executes, the service is started
       and can run in the background indefinitely. If you implement this, it is your responsibility to stop
       the service when its work is done, by calling stopSelf() or stopService(). (If you only want to
       provide binding, you don't need to implement this method.)

onBind()
      The system calls this method when another component wants to bind with the service (such as
      to perform RPC), by calling bindService(). In your implementation of this method, you must
      provide an interface that clients use to communicate with the service, by returning an IBinder.
      You must always implement this method, but if you don't want to allow binding, then you should
      return null.

onCreate()
     The system calls this method when the service is first created, to perform one-time setup
     procedures (before it calls either onStartCommand() or onBind()). If the service is already
     running, this method is not called.

onDestroy()
     The system calls this method when the service is no longer used and is being destroyed. Your
     service should implement this to clean up any resources such as threads, registered listeners,
     receivers, etc. This is the last call the service receives.
If a component starts the service by calling startService() (which results in a call to
onStartCommand()), then the service remains running until it stops itself with stopSelf() or another
component stops it by calling stopService().

If a component calls bindService() to create the service (and onStartCommand() is not called), then the
service runs only as long as the component is bound to it. Once the service is unbound from all clients,
the system destroys it.

The Android system will force-stop a service only when memory is low and it must recover system
resources for the activity that has user focus. If the service is bound to an activity that has user focus,
then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later),
then it will almost never be killed. Otherwise, if the service was started and is long-running, then the
system will lower its position in the list of background tasks over time and the service will become
highly susceptible to killing—if your service is started, then you must design it to gracefully handle
restarts by the system. If the system kills your service, it restarts it as soon as resources become
available again (though this also depends on the value you return from onStartCommand(), as
discussed later). For more information about when the system might destroy a service, see the
Processes and Threading document.

In the following sections, you'll see how you can create each type of service and how to use it from
other application components.

Declaring a service in the manifest

Like activities (and other components), you must declare all services in your application's manifest file.

To declare your service, add a <service> element as a child of the <application> element. For
example:

  <manifest ... >
   ...
   <application ... >
       <service android:name=".ExampleService" />
       ...
   </application>
  </manifest>


There are other attributes you can include in the <service> element to define properties such as
permissions required to start the service and the process in which the service should run. The
android:name attribute is the only required attribute—it specifies the class name of the service. Once
you publish your application, you should not change this name, because if you do, you might break
some functionality where explicit intents are used to reference your service (read the blog post, Things
That Cannot Change).

See the <service> element reference for more information about declaring your service in the manifest.
Just like an activity, a service can define intent filters that allow other components to invoke the service
using implicit intents. By declaring intent filters, components from any application installed on the
user's device can potentially start your service if your service declares an intent filter that matches the
intent another application passes to startService().

If you plan on using your service only locally (other applications do not use it), then you don't need to
(and should not) supply any intent filters. Without any intent filters, you must start the service using an
intent that explicitly names the service class. More information about starting a service is discussed
below.

Additionally, you can ensure that your service is private to your application only if you include the
android:exported attribute and set it to "false". This is effective even if your service supplies intent
filters.

For more information about creating intent filters for your service, see the Intents and Intent Filters
document.


Creating a Started Service

Targeting Android 1.6 or lower
If you're building an application for Android 1.6 or lower, you need to implement onStart(), instead of
onStartCommand() (in Android 2.0, onStart() was deprecated in favor of onStartCommand()).

For more information about providing compatibility with versions of Android older than 2.0, see the
onStartCommand() documentation.

A started service is one that another component starts by calling startService(), resulting in a call to the
service's onStartCommand() method.

When a service is started, it has a lifecycle that's independent of the component that started it and the
service can run in the background indefinitely, even if the component that started it is destroyed. As
such, the service should stop itself when its job is done by calling stopSelf(), or another component
can stop it by calling stopService().

An application component such as an activity can start the service by calling startService() and
passing an Intent that specifies the service and includes any data for the service to use. The service
receives this Intent in the onStartCommand() method.

For instance, suppose an activity needs to save some data to an online database. The activity can
start a companion service and deliver it the data to save by passing an intent to startService(). The
service receives the intent in onStartCommand(), connects to the Internet and performs the database
transaction. When the transaction is done, the service stops itself and it is destroyed.

  Caution: A services runs in the same process as the application in which it is declared and in the
  main thread of that application, by default. So, if your service performs intensive or blocking
  operations while the user interacts with an activity from the same application, the service will slow
down activity performance. To avoid impacting application performance, you should start a new
      thread inside the service.

    Traditionally, there are two classes you can extend to create a started service:

    Service

          This is the base class for all services. When you extend this class, it's important that you create
          a new thread in which to do all the service's work, because the service uses your application's
          main thread, by default, which could slow the performance of any activity your application is
          running.

    IntentService
           This is a subclass of Service that uses a worker thread to handle all start requests, one at a
           time. This is the best option if you don't require that your service handle multiple requests
           simultaneously. All you need to do is implement onHandleIntent(), which receives the intent for
           each start request so you can do the background work.

    The following sections describe how you can implement your service using either one for these
    classes.

    Extending the IntentService class

    Because most started services don't need to handle multiple requests simultaneously (which can
    actually be a dangerous multi-threading scenario), it's probably best if you implement your service
    using the IntentService class.

    The IntentService does the following:

   Creates a default worker thread that executes all intents delivered to onStartCommand() separate from
    your application's main thread.
   Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so
    you never have to worry about multi-threading.
   Stops the service after all start requests have been handled, so you never have to call stopSelf().
   Provides default implementation of onBind() that returns null.
   Provides a default implementation of onStartCommand() that sends the intent to the work queue and
    then to your onHandleIntent() implementation.

    All this adds up to the fact that all you need to do is implement onHandleIntent() to do the work
    provided by the client. (Though, you also need to provide a small constructor for the service.)

    Here's an example implementation of IntentService:

      public class HelloIntentService extends IntentService {

       /**
        * A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
       */
      public HelloIntentService() {
          super("HelloIntentService");
      }

      /**
       * The IntentService calls this method from the default worker thread with
       * the intent that started the service. When this method returns, IntentService
       * stops the service, as appropriate.
       */
      @Override
      protected void onHandleIntent(Intent intent) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
             synchronized (this) {
                try {
                   wait(endTime - System.currentTimeMillis());
                } catch (Exception e) {
                }
             }
          }
      }
  }


That's all you need: a constructor and an implementation of onHandleIntent().

If you decide to also override other callback methods, such as onCreate(), onStartCommand(), or
onDestroy(), be sure to call the super implementation, so that the IntentService can properly handle
the life of the worker thread.

For example, onStartCommand() must return the default implementation (which is how the intent gets
delivered to onHandleIntent()):

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
  }


Besides onHandleIntent(), the only method from which you don't need to call the super class is
onBind() (but you only need to implement that if your service allows binding).

In the next section, you'll see how the same kind of service is implemented when extending the base
Service class, which is a lot more code, but which might be appropriate if you need to handle
simultaneous start requests.
Extending the Service class

As you saw in the previous section, using IntentService makes your implementation of a started
service very simple. If, however, you require your service to perform multi-threading (instead of
processing start requests through a work queue), then you can extend the Service class to handle
each intent.

For comparison, the following example code is an implementation of the Service class that performs
the exact same work as the example above using IntentService. That is, for each start request, it uses
a worker thread to perform the job and processes only one request at a time.

  public class HelloService extends Service {
   private Looper mServiceLooper;
   private ServiceHandler mServiceHandler;

   // Handler that receives messages from the thread
   private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
        super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
        // Normally we would do some work here, like download a file.
        // For our sample, we just sleep for 5 seconds.
        long endTime = System.currentTimeMillis() + 5*1000;
        while (System.currentTimeMillis() < endTime) {
            synchronized (this) {
              try {
                 wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
            }
        }
        // Stop the service using the startId, so that we don't stop
        // the service in the middle of handling another job
        stopSelf(msg.arg1);
      }
   }

   @Override
   public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
          Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
          mServiceHandler = new ServiceHandler(mServiceLooper);
      }

      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

           // For each start request, send a message to start a job and deliver the
           // start ID so we know which request we're stopping when we finish the job
           Message msg = mServiceHandler.obtainMessage();
           msg.arg1 = startId;
           mServiceHandler.sendMessage(msg);

           // If we get killed, after returning from here, restart
           return START_STICKY;
      }

      @Override
      public IBinder onBind(Intent intent) {
        // We don't provide binding, so return null
        return null;
      }

      @Override
      public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      }
  }


As you can see, it's a lot more work than using IntentService.

However, because you handle each call to onStartCommand() yourself, you can perform multiple
requests simultaneously. That's not what this example does, but if that's what you want, then you can
create a new thread for each request and run them right away (instead of waiting for the previous
request to finish).

Notice that the onStartCommand() method must return an integer. The integer is a value that
describes how the system should continue the service in the event that the system kills it (as
discussed above, the default implementation for IntentService handles this for you, though you are
able to modify it). The return value from onStartCommand() must be one of the following constants:

START_NOT_STICKY

           If the system kills the service after onStartCommand() returns, do not recreate the service,
           unless there are pending intents to deliver. This is the safest option to avoid running your
           service when not necessary and when your application can simply restart any unfinished jobs.

START_STICKY
If the system kills the service after onStartCommand() returns, recreate the service and call
       onStartCommand(), but do not redeliver the last intent. Instead, the system calls
       onStartCommand() with a null intent, unless there were pending intents to start the service, in
       which case, those intents are delivered. This is suitable for media players (or similar services)
       that are not executing commands, but running indefinitely and waiting for a job.

START_REDELIVER_INTENT
     If the system kills the service after onStartCommand() returns, recreate the service and call
     onStartCommand() with the last intent that was delivered to the service. Any pending intents are
     delivered in turn. This is suitable for services that are actively performing a job that should be
     immediately resumed, such as downloading a file.

For more details about these return values, see the linked reference documentation for each constant.

Starting a Service

You can start a service from an activity or other application component by passing an Intent (specifying
the service to start) to startService(). The Android system calls the service's onStartCommand()
method and passes it the Intent. (You should never call onStartCommand() directly.)

For example, an activity can start the example service in the previous section (HelloSevice) using an
explicit intent with startService():

  Intent intent = new Intent(this, HelloService.class);
  startService(intent);


The startService() method returns immediately and the Android system calls the service's
onStartCommand() method. If the service is not already running, the system first calls onCreate(), then
calls onStartCommand().

If the service does not also provide binding, the intent delivered with startService() is the only mode of
communication between the application component and the service. However, if you want the service
to send a result back, then the client that starts the service can create a PendingIntent for a broadcast
(with getBroadcast()) and deliver it to the service in the Intent that starts the service. The service can
then use the broadcast to deliver a result.

Multiple requests to start the service result in multiple corresponding calls to the service's
onStartCommand(). However, only one request to stop the service (with stopSelf() or stopService()) is
required to stop it.

Stopping a service

A started service must manage its own lifecycle. That is, the system does not stop or destroy the
service unless it must recover system memory and the service continues to run after
onStartCommand() returns. So, the service must stop itself by calling stopSelf() or another component
can stop it by calling stopService().
Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as
possible.

However, if your service handles multiple requests to onStartCommand() concurrently, then you
shouldn't stop the service when you're done processing a start request, because you might have since
received a new start request (stopping at the end of the first request would terminate the second one).
To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is
always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of
the start request (the startId delivered to onStartCommand()) to which your stop request corresponds.
Then if the service received a new start request before you were able to call stopSelf(int), then the ID
will not match and the service will not stop.

  Caution: It's important that your application stops its services when it's done working, to avoid
  wasting system resources and consuming battery power. If necessary, other components can stop
  the service by calling stopService(). Even if you enable binding for the service, you must always
  stop the service yourself if it ever received a call to onStartCommand().

For more information about the lifecycle of a service, see the section below about Managing the
Lifecycle of a Service.


Creating a Bound Service

A bound service is one that allows application components to bind to it by calling bindService() in order
to create a long-standing connection (and generally does not allow components to start it by calling
startService()).

You should create a bound service when you want to interact with the service from activities and other
components in your application or to expose some of your application's functionality to other
applications, through interprocess communication (IPC).

To create a bound service, you must implement the onBind() callback method to return an IBinder that
defines the interface for communication with the service. Other application components can then call
bindService() to retrieve the interface and begin calling methods on the service. The service lives only
to serve the application component that is bound to it, so when there are no components bound to the
service, the system destroys it (you do not need to stop a bound service in the way you must when the
service is started through onStartCommand()).

To create a bound service, the first thing you must do is define the interface that specifies how a client
can communicate with the service. This interface between the service and a client must be an
implementation of IBinder and is what your service must return from the onBind() callback method.
Once the client receives the IBinder, it can begin interacting with the service through that interface.

Multiple clients can bind to the service at once. When a client is done interacting with the service, it
calls unbindService() to unbind. Once there are no clients bound to the service, the system destroys
the service.
There are multiple ways to implement a bound service and the implementation is more complicated
than a started service, so the bound service discussion appears in a separate document about Bound
Services.


Sending Notifications to the User

Once running, a service can notify the user of events using Toast Notifications or Status Bar
Notifications.

A toast notification is a message that appears on the surface of the current window for a moment then
disappears, while a status bar notification provides an icon in the status bar with a message, which the
user can select in order to take an action (such as start an activity).

Usually, a status bar notification is the best technique when some background work has completed
(such as a file completed downloading) and the user can now act on it. When the user selects the
notification from the expanded view, the notification can start an activity (such as to view the
downloaded file).

See the Toast Notifications or Status Bar Notifications developer guides for more information.


Running a Service in the Foreground

A foreground service is a service that's considered to be something the user is actively aware of and
thus not a candidate for the system to kill when low on memory. A foreground service must provide a
notification for the status bar, which is placed under the "Ongoing" heading, which means that the
notification cannot be dismissed unless the service is either stopped or removed from the foreground.

For example, a music player that plays music from a service should be set to run in the foreground,
because the user is explicitly aware of its operation. The notification in the status bar might indicate the
current song and allow the user to launch an activity to interact with the music player.

To request that your service run in the foreground, call startForeground(). This method takes two
parameters: an integer that uniquely identifies the notification and the Notification for the status bar.
For example:

  Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
  Intent notificationIntent = new Intent(this, ExampleActivity.class);
  PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
  notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
  startForeground(ONGOING_NOTIFICATION, notification);


To remove the service from the foreground, call stopForeground(). This method takes a boolean,
indicating whether to remove the status bar notification as well. This method does not stop the service.
However, if you stop the service while it's still running in the foreground, then the notification is also
    removed.

      Note: The methods startForeground() and stopForeground() were introduced in Android 2.0 (API
      Level 5). In order to run your service in the foreground on older versions of the platform, you must
      use the previous setForeground() method—see the startForeground() documentation for
      information about how to provide backward compatibility.

    For more information about notifications, see Creating Status Bar Notifications.


    Managing the Lifecycle of a Service

    The lifecycle of a service is much simpler than that of an activity. However, it's even more important
    that you pay close attention to how your service is created and destroyed, because a service can run
    in the background without the user being aware.

    The service lifecycle—from when it's created to when it's destroyed—can follow two different paths:

   A started service

    The service is created when another component calls startService(). The service then runs indefinitely
    and must stop itself by calling stopSelf(). Another component can also stop the service by calling
    stopService(). When the service is stopped, the system destroys it..

   A bound service

    The service is created when another component (a client) calls bindService(). The client then
    communicates with the service through an IBinder interface. The client can close the connection by
    calling unbindService(). Multiple clients can bind to the same service and when all of them unbind, the
    system destroys the service. (The service does not need to stop itself.)
    These two paths are not entirely separate. That is, you can bind to a service that was already started
    with startService(). For example, a background music service could be started by calling startService()
    with an Intent that identifies the music to play. Later, possibly when the user wants to exercise some
    control over the player or get information about the current song, an activity can bind to the service by
    calling bindService(). In cases like this, stopService() or stopSelf() does not actually stop the service
    until all clients unbind.

    Implementing the lifecycle callbacks

    Like an activity, a service has lifecycle callback methods that you can implement to monitor changes in
    the service's state and perform work at the appropriate times. The following skeleton service
    demonstrates each of the lifecycle methods:
Figure 2. The service lifecycle. The diagram on the left shows the lifecycle when the service is created
with startService() and the diagram on the right shows the lifecycle when the service is created with
bindService().

  public class ExampleService extends Service {
    int mStartMode;    // indicates how to behave if the service is killed
    IBinder mBinder;   // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
      // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
      // The service is starting, due to a call to startService()
      return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
      // A client is binding to the service with bindService()
      return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
      // All clients have unbound with unbindService()
return mAllowRebind;
          }
          @Override
          public void onRebind(Intent intent) {
            // A client is binding to the service with bindService(),
            // after onUnbind() has already been called
          }
          @Override
          public void onDestroy() {
            // The service is no longer used and is being destroyed
          }
      }


      Note: Unlike the activity lifecycle callback methods, you are not required to call the superclass
      implementation of these callback methods.

    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(), then stop the thread in onDestroy().

    The onCreate() and onDestroy() methods are called for all services, whether they're created by
    startService() or bindService().

   The active lifetime of a service begins with a call to either onStartCommand() or onBind(). Each
    method is handed the Intent that was passed to either startService() or bindService(), respectively.

    If the service is started, the active lifetime ends the same time that the entire lifetime ends (the service
    is still active even after onStartCommand() returns). If the service is bound, the active lifetime ends
    when onUnbind() returns.

      Note: Although a started service is stopped by a call to either stopSelf() or stopService(), there is
      not a respective callback for the service (there's no onStop() callback). So, unless the service is
      bound to a client, the system destroys it when the service is stopped—onDestroy() is the only
      callback received.

    Figure 2 illustrates the typical callback methods for a service. Although the figure separates services
    that are created by 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, a service that was initially
    started with onStartCommand() (by a client calling startService()) can still receive a call to onBind()
    (when a client calls bindService()).

    For more information about creating a service that provides binding, see the Bound Services
    document, which includes more information about the onRebind() callback method in the section about
    Managing the Lifecycle of a Bound Service.
Bound Services.

A bound service is the server in a client-server interface. A bound service allows components (such as
activities) to bind to the service, send requests, receive responses, and even perform interprocess
communication (IPC). A bound service typically lives only while it serves another application
component and does not run in the background indefinitely.

This document shows you how to create a bound service, including how to bind to the service from
other application components. However, you should also refer to the Services document for additional
information about services in general, such as how to deliver notifications from a service, set the
service to run in the foreground, and more.


The Basics

A bound service is an implementation of the Service class that allows other applications to bind to it
and interact with it. To provide binding for a service, you must implement the onBind() callback
method. This method returns an IBinder object that defines the programming interface that clients can
use to interact with the service.

Binding to a Started Service

As discussed in the Services document, you can create a service that is both started and bound. That
is, the service can be started by calling startService(), which allows the service to run indefinitely, and
also allow a client to bind to the service by calling bindService().

If you do allow your service to be started and bound, then when the service has been started, the
system does not destroy the service when all clients unbind. Instead, you must explicitly stop the
service, by calling stopSelf() or stopService().

Although you should usually implement either onBind() or onStartCommand(), it's sometimes
necessary to implement both. For example, a music player might find it useful to allow its service to run
indefinitely and also provide binding. This way, an activity can start the service to play some music and
the music continues to play even if the user leaves the application. Then, when the user returns to the
application, the activity can bind to the service to regain control of playback.

Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information
about the service lifecycle when adding binding to a started service.

A client can bind to the service by calling bindService(). When it does, it must provide an
implementation of ServiceConnection, which monitors the connection with the service. The
bindService() method returns immediately without a value, but when the Android system creates the
connection between the client and service, it calls onServiceConnected() on the ServiceConnection, to
deliver the IBinder that the client can use to communicate with the service.

Multiple clients can connect to the service at once. However, the system calls your service's onBind()
method to retrieve the IBinder only when the first client binds. The system then delivers the same
IBinder to any additional clients that bind, without calling onBind() again.
When the last client unbinds from the service, the system destroys the service (unless the service was
also started by startService()).

When you implement your bound service, the most important part is defining the interface that your
onBind() callback method returns. There are a few different ways you can define your service's IBinder
interface and the following section discusses each technique.


Creating a Bound Service

When creating a service that provides binding, you must provide an IBinder that provides the
programming interface that clients can use to interact with the service. There are three ways you can
define the interface:

Extending the Binder class

      If your service is private to your own application and runs in the same process as the client
      (which is common), you should create your interface by extending the Binder class and
      returning an instance of it from onBind(). The client receives the Binder and can use it to directly
      access public methods available in either the Binder implementation or even the Service.

      This is the preferred technique when your service is merely a background worker for your own
      application. The only reason you would not create your interface this way is because your
      service is used by other applications or across separate processes.
Using a Messenger

      If you need your interface to work across different processes, you can create an interface for the
      service with a Messenger. In this manner, the service defines a Handler that responds to
      different types of Message objects. This Handler is the basis for a Messenger that can then
      share an IBinder with the client, allowing the client to send commands to the service using
      Message objects. Additionally, the client can define a Messenger of its own so the service can
      send messages back.

      This is the simplest way to perform interprocess communication (IPC), because the Messenger
      queues all requests into a single thread so that you don't have to design your service to be
      thread-safe.
Using AIDL

      AIDL (Android Interface Definition Language) performs all the work to decompose objects into
      primitives that the operating system can understand and marshall them across processes to
      perform IPC. The previous technique, using a Messenger, is actually based on AIDL as its
      underlying structure. As mentioned above, the Messenger creates a queue of all the client
      requests in a single thread, so the service receives requests one at a time. If, however, you
      want your service to handle multiple requests simultaneously, then you can use AIDL directly. In
      this case, your service must be capable of multi-threading and be built thread-safe.
To use AIDL directly, you must create an .aidl file that defines the programming interface. The
          Android SDK tools use this file to generate an abstract class that implements the interface and
          handles IPC, which you can then extend within your service.

     Note: Most applications should not use AIDL to create a bound service, because it may require
     multithreading capabilities and can result in a more complicated implementation. As such, AIDL is
     not suitable for most applications and this document does not discuss how to use it for your
     service. If you're certain that you need to use AIDL directly, see the AIDL document.

   Extending the Binder class

   If your service is used only by the local application and does not need to work across processes, then
   you can implement your own Binder class that provides your client direct access to public methods in
   the service.

     Note: This works only if the client and service are in the same application and process, which is
     most common. For example, this would work well for a music application that needs to bind an
     activity to its own service that's playing music in the background.

   Here's how to set it up:

1. In your service, create an instance of Binder that either:
o contains public methods that the client can call
o returns the current Service instance, which has public methods the client can call
o or, returns an instance of another class hosted by the service with public methods the client can call
2. Return this instance of Binder from the onBind() callback method.
3. In the client, receive the Binder from the onServiceConnected() callback method and make calls to the
   bound service using the methods provided.

     Note: The reason the service and client must be in the same application is so the client can cast
     the returned object and properly call its APIs. The service and client must also be in the same
     process, because this technique does not perform any marshalling across processes.

   For example, here's a service that provides clients access to methods in the service through a Binder
   implementation:

     public class LocalService extends Service {
       // Binder given to clients
       private final IBinder mBinder = new LocalBinder();
       // Random number generator
       private final Random mGenerator = new Random();

       /**
        * Class used for the client Binder. Because we know this service always
        * runs in the same process as its clients, we don't need to deal with IPC.
        */
       public class LocalBinder extends Binder {
           LocalService getService() {
             // Return this instance of LocalService so clients can call public methods
return LocalService.this;
          }
      }

      @Override
      public IBinder onBind(Intent intent) {
        return mBinder;
      }

      /** method for clients */
      public int getRandomNumber() {
        return mGenerator.nextInt(100);
      }
  }


The LocalBinder provides the getService() method for clients to retrieve the current instance of
LocalService. This allows clients to call public methods in the service. For example, clients can call
getRandomNumber() from the service.

Here's an activity that binds to LocalService and calls getRandomNumber() when a button is clicked:

  public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      }

      @Override
      protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
      }

      @Override
      protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
      }

      /** Called when a button is clicked (the button in the layout file attaches to
        * this method with the android:onClick attribute) */
      public void onButtonClick(View v) {
          if (mBound) {
              // Call a method from the LocalService.
              // However, if this call were something that might hang, then this request should
              // occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
                   Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
               }
          }

          /** Defines callbacks for service binding, passed to bindService() */
          private ServiceConnection mConnection = new ServiceConnection() {

               @Override
               public void onServiceConnected(ComponentName className,
                    IBinder service) {
                 // We've bound to LocalService, cast the IBinder and get LocalService instance
                 LocalBinder binder = (LocalBinder) service;
                 mService = binder.getService();
                 mBound = true;
               }

               @Override
               public void onServiceDisconnected(ComponentName arg0) {
                 mBound = false;
               }
          };
      }


    The above sample shows how the client binds to the service using an implementation of
    ServiceConnection and the onServiceConnected() callback. The next section provides more
    information about this process of binding to the service.

      Note: The example above doesn't explicitly unbind from the service, but all clients should unbind
      at an appropriate time (such as when the activity pauses).

    For more sample code, see the LocalService.java class and the LocalServiceActivities.java class in
    ApiDemos.

    Using a Messenger
    Compared to AIDL
    When you need to perform IPC, using a Messenger for your interface is simpler than implementing it
    with AIDL, because Messenger queues all calls to the service, whereas, a pure AIDL interface sends
    simultaneous requests to the service, which must then handle multi-threading.

    For most applications, the service doesn't need to perform multi-threading, so using a Messenger
    allows the service to handle one call at a time. If it's important that your service be multi-threaded, then
    you should use AIDL to define your interface.

    If you need your service to communicate with remote processes, then you can use a Messenger to
    provide the interface for your service. This technique allows you to perform interprocess
    communication (IPC) without the need to use AIDL.

    Here's a summary of how to use a Messenger:

   The service implements a Handler that receives a callback for each call from a client.
   The Handler is used to create a Messenger object (which is a reference to the Handler).
   The Messenger creates an IBinder that the service returns to clients from onBind().
   Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the
    client uses to send Message objects to the service.
   The service receives each Message in its Handler—specifically, in the handleMessage() method.

    In this way, there are no "methods" for the client to call on the service. Instead, the client delivers
    "messages" (Message objects) that the service receives in its Handler.

    Here's a simple example service that uses a Messenger interface:

      public class MessengerService extends Service {
        /** Command to the service to display a message */
        static final int MSG_SAY_HELLO = 1;

          /**
           * Handler of incoming messages from clients.
           */
          class IncomingHandler extends Handler {
              @Override
              public void handleMessage(Message msg) {
                switch (msg.what) {
                   case MSG_SAY_HELLO:
                      Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                      break;
                   default:
                      super.handleMessage(msg);
                }
              }
          }

          /**
           * Target we publish for clients to send messages to IncomingHandler.
           */
          final Messenger mMessenger = new Messenger(new IncomingHandler());

          /**
           * When binding to the service, we return an interface to our messenger
           * for sending messages to the service.
           */
          @Override
          public IBinder onBind(Intent intent) {
              Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
              return mMessenger.getBinder();
          }
      }


    Notice that the handleMessage() method in the Handler is where the service receives the incoming
    Message and decides what to do, based on the what member.
All that a client needs to do is create a Messenger based on the IBinder returned by the service and
send a message using send(). For example, here's a simple activity that binds to the service and
delivers the MSG_SAY_HELLO message to the service:

  public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
          // This is called when the connection with the service has been
          // established, giving us the object we can use to
          // interact with the service. We are communicating with the
          // service using a Messenger, so here we get a client-side
          // representation of that from the raw IBinder object.
          mService = new Messenger(service);
          mBound = true;
        }

         public void onServiceDisconnected(ComponentName className) {
           // This is called when the connection with the service has been
           // unexpectedly disconnected -- that is, its process crashed.
           mService = null;
           mBound = false;
         }
    };

    public void sayHello(View v) {
      if (!mBound) return;
      // Create and send a message to the service, using a supported 'what' value
      Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
      try {
          mService.send(msg);
      } catch (RemoteException e) {
          e.printStackTrace();
      }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    }
@Override
         protected void onStart() {
           super.onStart();
           // Bind to the service
           bindService(new Intent(this, MessengerService.class), mConnection,
              Context.BIND_AUTO_CREATE);
         }

         @Override
         protected void onStop() {
           super.onStop();
           // Unbind from the service
           if (mBound) {
               unbindService(mConnection);
               mBound = false;
           }
         }
     }


   Notice that this example does not show how the service can respond to the client. If you want the
   service to respond, then you need to also create a Messenger in the client. Then when the client
   receives the onServiceConnected() callback, it sends a Message to the service that includes the
   client's Messenger in the replyTo parameter of the send() method.

   You can see an example of how to provide two-way messaging in the MessengerService.java (service)
   and MessengerServiceActivities.java (client) samples.


   Binding to a Service

   Application components (clients) can bind to a service by calling bindService(). The Android system
   then calls the service's onBind() method, which returns an IBinder for interacting with the service.

   The binding is asynchronous. bindService() returns immediately and does not return the IBinder to the
   client. To receive the IBinder, the client must create an instance of ServiceConnection and pass it to
   bindService(). The ServiceConnection includes a callback method that the system calls to deliver the
   IBinder.

     Note: Only activities, services, and content providers can bind to a service—you cannot bind to a
     service from a broadcast receiver.

   So, to bind to a service from your client, you must:

1. Implement ServiceConnection.

   Your implementation must override two callback methods:
   onServiceConnected()

          The system calls this to deliver the IBinder returned by the service's onBind() method.
onServiceDisconnected()
          The Android system calls this when the connection to the service is unexpectedly lost, such as
          when the service has crashed or has been killed. This is not called when the client unbinds.

2. Call bindService(), passing the ServiceConnection implementation.
3. When the system calls your onServiceConnected() callback method, you can begin making calls to the
   service, using the methods defined by the interface.
4. To disconnect from the service, call unbindService().

    When your client is destroyed, it will unbind from the service, but you should always unbind when
    you're done interacting with the service or when your activity pauses so that the service can shutdown
    while its not being used. (Appropriate times to bind and unbind is discussed more below.)
    For example, the following snippet connects the client to the service created above by extending the
    Binder class, so all it must do is cast the returned IBinder to the LocalService class and request the
    LocalService instance:

      LocalService mService;
      private ServiceConnection mConnection = new ServiceConnection() {
         // Called when the connection with the service is established
         public void onServiceConnected(ComponentName className, IBinder service) {
            // Because we have bound to an explicit
            // service that is running in our own process, we can
            // cast its IBinder to a concrete class and directly access it.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
         }

           // Called when the connection with the service disconnects unexpectedly
           public void onServiceDisconnected(ComponentName className) {
              Log.e(TAG, "onServiceDisconnected");
              mBound = false;
           }
      };


    With this ServiceConnection, the client can bind to a service by passing this it to bindService(). For
    example:

      Intent intent = new Intent(this, LocalService.class);
      bindService(intent, mConnection, Context.BIND_AUTO_CREATE);


   The first parameter of bindService() is an Intent that explicitly names the service to bind (thought the
    intent could be implicit).
   The second parameter is the ServiceConnection object.
   The third parameter is a flag indicating options for the binding. It should usually be
    BIND_AUTO_CREATE in order to create the service if its not already alive. Other possible values are
    BIND_DEBUG_UNBIND and BIND_NOT_FOREGROUND, or 0 for none.

    Additional notes
    Here are some important notes about binding to a service:

   You should always trap DeadObjectException exceptions, which are thrown when the connection has
    broken. This is the only exception thrown by remote methods.
   Objects are reference counted across processes.
   You should usually pair the binding and unbinding during matching bring-up and tear-down moments
    of the client's lifecycle. For example:
o   If you only need to interact with the service while your activity is visible, you should bind during
    onStart() and unbind during onStop().
o   If you want your activity to receive responses even while it is stopped in the background, then you can
    bind during onCreate() and unbind during onDestroy(). Beware that this implies that your activity needs
    to use the service the entire time it's running (even in the background), so if the service is in another
    process, then you increase the weight of the process and it becomes more likely that the system will
    kill it.
    Note: You should usually not bind and unbind during your activity's onResume() and onPause(),
    because these callbacks occur at every lifecycle transition and you should keep the processing that
    occurs at these transitions to a minimum. Also, if multiple activities in your application bind to the same
    service and there is a transition between two of those activities, the service may be destroyed and
    recreated as the current activity unbinds (during pause) before the next one binds (during resume).
    (This activity transition for how activities coordinate their lifecycles is described in the Activities
    document.)
    For more sample code, showing how to bind to a service, see the RemoteService.java class in
    ApiDemos.
Managing the Lifecycle of a Bound Service

                                                                   Figure 1. The lifecycle for a service
                                                                   that is started and also allows binding.

                                                                   When a service is unbound from all
                                                                   clients, the Android system destroys it
                                                                   (unless it was also started with
                                                                   onStartCommand()). As such, you
                                                                   don't have to manage the lifecycle of
                                                                   your service if it's purely a bound
                                                                   service—the Android system manages
                                                                   it for you based on whether it is bound
                                                                   to any clients.

                                                                   However, if you choose to implement
                                                                   the onStartCommand() callback
                                                                   method, then you must explicitly stop
                                                                   the service, because the service is
                                                                   now considered to be started. In this
                                                                   case, the service runs until the service
                                                                   stops itself with stopSelf() or another
                                                                   component calls stopService(),
                                                                   regardless of whether it is bound to
                                                                   any clients.

Additionally, if your service is started and accepts binding, then when the system calls your onUnbind()
method, you can optionally return true if you would like to receive a call to onRebind() the next time a
client binds to the service (instead of receiving a call to onBind()). onRebind() returns void, but the
client still receives the IBinder in its onServiceConnected() callback. Below, figure 1 illustrates the logic
for this kind of lifecycle.

For more information about the lifecycle of an started service, see the Services document.

Content Providers

Content providers store and retrieve data and make it accessible to all applications. They're the only
way to share data across applications; there's no common storage area that all Android packages can
access.

Android ships with a number of content providers for common data types (audio, video, images,
personal contact information, and so on). You can see some of them listed in the android.provider
package. You can query these providers for the data they contain (although, for some, you must
acquire the proper permission to read the data).
If you want to make your own data public, you have two options: You can create your own content
provider (a ContentProvider subclass) or you can add the data to an existing provider — if there's one
that controls the same type of data and you have permission to write to it.

This document is an introduction to using content providers. After a brief discussion of the
fundamentals, it explores how to query a content provider, how to modify data controlled by a provider,
and how to create a content provider of your own.


Content Provider Basics

How a content provider actually stores its data under the covers is up to its designer. But all content
providers implement a common interface for querying the provider and returning results — as well as
for adding, altering, and deleting data. It's an interface that clients use indirectly, most generally
through ContentResolver objects. You get a ContentResolver by calling getContentResolver() from
within the implementation of an Activity or other application component:

  ContentResolver cr = getContentResolver();


You can then use the ContentResolver's methods to interact with whatever content providers you're
interested in. When a query is initiated, the Android system identifies the content provider that's the
target of the query and makes sure that it is up and running. The system instantiates all
ContentProvider objects; you never need to do it on your own. In fact, you never deal directly with
ContentProvider objects at all. Typically, there's just a single instance of each type of ContentProvider.
But it can communicate with multiple ContentResolver objects in different applications and processes.
The interaction between processes is handled by the ContentResolver and ContentProvider classes.

The data model

Content providers expose their data as a simple table on a database model, where each row is a
record and each column is data of a particular type and meaning. For example, information about
people and their phone numbers might be exposed as follows:

  _ID    NUMBER              NUMBER_KEY          LABEL               NAME           TYPE


  13     (425) 555 6677      425 555 6677        Kirkland office     Bully Pulpit   TYPE_WORK


  44     (212) 555-1234      212 555 1234        NY apartment        Alan Vain      TYPE_HOME


  45     (212) 555-6657      212 555 6657        Downtown office     Alan Vain      TYPE_MOBILE


  53     201.555.4433        201 555 4433        Love Nest           Rex Cars       TYPE_HOME
Every record includes a numeric _ID field that uniquely identifies the record within the table. IDs can be
    used to match records in related tables — for example, to find a person's phone number in one table
    and pictures of that person in another.

    A query returns a Cursor object that can move from record to record and column to column to read the
    contents of each field. It has specialized methods for reading each type of data. So, to read a field, you
    must know what type of data the field contains. (There's more on query results and Cursor objects
    later.)

    URIs

    Each content provider exposes a public URI (wrapped as a Uri object) that uniquely identifies its data
    set. A content provider that controls multiple data sets (multiple tables) exposes a separate URI for
    each one. All URIs for providers begin with the string "content://". The content: scheme identifies the
    data as being controlled by a content provider.

    If you're defining a content provider, it's a good idea to also define a constant for its URI, to simplify
    client code and make future updates cleaner. Android defines CONTENT_URI constants for all the
    providers that come with the platform. For example, the URI for the table that matches phone numbers
    to people and the URI for the table that holds pictures of people (both controlled by the Contacts
    content provider) are:

        android.provider.Contacts.Phones.CONTENT_URI
        android.provider.Contacts.Photos.CONTENT_URI

    The URI constant is used in all interactions with the content provider. Every ContentResolver method
    takes the URI as its first argument. It's what identifies which provider the ContentResolver should talk
    to and which table of the provider is being targeted.


    Querying a Content Provider

    You need three pieces of information to query a content provider:

   The URI that identifies the provider
   The names of the data fields you want to receive
   The data types for those fields

    If you're querying a particular record, you also need the ID for that record.

    Making the query

    To query a content provider, you can use either the ContentResolver.query() method or the
    Activity.managedQuery() method. Both methods take the same set of arguments, and both return a
    Cursor object. However, managedQuery() causes the activity to manage the life cycle of the Cursor. A
    managed Cursor handles all of the niceties, such as unloading itself when the activity pauses, and
requerying itself when the activity restarts. You can ask an Activity to begin managing an unmanaged
    Cursor object for you by calling Activity.startManagingCursor().

    The first argument to either query() or managedQuery() is the provider URI — the CONTENT_URI
    constant that identifies a particular ContentProvider and data set (see URIs earlier).

    To restrict a query to just one record, you can append the _ID value for that record to the URI — that
    is, place a string matching the ID as the last segment of the path part of the URI. For example, if the ID
    is 23, the URI would be:

        content://. . . ./23

    There are some helper methods, particularly ContentUris.withAppendedId() and
    Uri.withAppendedPath(), that make it easy to append an ID to a URI. Both are static methods that
    return a Uri object with the ID added. So, for example, if you were looking for record 23 in the database
    of people contacts, you might construct a query as follows:

      import android.provider.Contacts.People;
      import android.content.ContentUris;
      import android.net.Uri;
      import android.database.Cursor;

      // Use the ContentUris method to produce the base URI for the contact with _ID == 23.
      Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);

      // Alternatively, use the Uri method to produce the base URI.
      // It takes a string rather than an integer.
      Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");

      // Then query for this specific record:
      Cursor cur = managedQuery(myPerson, null, null, null, null);


    The other arguments to the query() and managedQuery() methods delimit the query in more detail.
    They are:

   The names of the data columns that should be returned. A null value returns all columns. Otherwise,
    only columns that are listed by name are returned. All the content providers that come with the
    platform define constants for their columns. For example, the android.provider.Contacts.Phones class
    defines constants for the names of the columns in the phone table illustrated earlier &mdash _ID,
    NUMBER, NUMBER_KEY, NAME, and so on.
   A filter detailing which rows to return, formatted as an SQL WHERE clause (excluding the WHERE
    itself). A null value returns all rows (unless the URI limits the query to a single record).
   Selection arguments.
   A sorting order for the rows that are returned, formatted as an SQL ORDER BY clause (excluding the
    ORDER BY itself). A null value returns the records in the default order for the table, which may be
    unordered.
Let's look at an example query to retrieve a list of contact names and their primary phone numbers:

  import android.provider.Contacts.People;
  import android.database.Cursor;

  // Form an array specifying which columns to return.
  String[] projection = new String[] {
                       People._ID,
                       People._COUNT,
                       People.NAME,
                       People.NUMBER
                    };

  // Get the base URI for the People table in the Contacts content provider.
  Uri contacts = People.CONTENT_URI;

  // Make the query.
  Cursor managedCursor = managedQuery(contacts,
                 projection, // Which columns to return
                 null,     // Which rows to return (all rows)
                 null,     // Selection arguments (none)
                 // Put the results in ascending order by name
                 People.NAME + " ASC");


This query retrieves data from the People table of the Contacts content provider. It gets the name,
primary phone number, and unique record ID for each contact. It also reports the number of records
that are returned as the _COUNT field of each record.

The constants for the names of the columns are defined in various interfaces — _ID and _COUNT in
BaseColumns, NAME in PeopleColumns, and NUMBER in PhoneColumns. The Contacts.People
class implements each of these interfaces, which is why the code example above could refer to them
using just the class name.

What a query returns

A query returns a set of zero or more database records. The names of the columns, their default order,
and their data types are specific to each content provider. But every provider has an _ID column,
which holds a unique numeric ID for each record. Every provider can also report the number of records
returned as the _COUNT column; its value is the same for all rows.

Here is an example result set for the query in the previous section:

   _ID       _COUNT             NAME               NUMBER


    44           3             Alan Vain         212 555 1234
13            3            Bully Pulpit     425 555 6677


      53            3             Rex Cars        201 555 4433

The retrieved data is exposed by a Cursor object that can be used to iterate backward or forward
through the result set. You can use this object only to read the data. To add, modify, or delete data,
you must use a ContentResolver object.

Reading retrieved data

The Cursor object returned by a query provides access to a recordset of results. If you have queried
for a specific record by ID, this set will contain only one value. Otherwise, it can contain multiple
values. (If there are no matches, it can also be empty.) You can read data from specific fields in the
record, but you must know the data type of the field, because the Cursor object has a separate method
for reading each type of data — such as getString(), getInt(), and getFloat(). (However, for most types,
if you call the method for reading strings, the Cursor object will give you the String representation of
the data.) The Cursor lets you request the column name from the index of the column, or the index
number from the column name.

The following snippet demonstrates reading names and phone numbers from the query illustrated
earlier:

  import android.provider.Contacts.People;

  private void getColumnData(Cursor cur){
     if (cur.moveToFirst()) {

           String name;
           String phoneNumber;
           int nameColumn = cur.getColumnIndex(People.NAME);
           int phoneColumn = cur.getColumnIndex(People.NUMBER);
           String imagePath;

           do {
             // Get the field values
             name = cur.getString(nameColumn);
             phoneNumber = cur.getString(phoneColumn);

             // Do something with the values.
             ...

           } while (cur.moveToNext());

      }
  }
If a query can return binary data, such as an image or sound, the data may be directly entered in the
    table or the table entry for that data may be a string specifying a content: URI that you can use to get
    the data. In general, smaller amounts of data (say, from 20 to 50K or less) are most often directly
    entered in the table and can be read by calling Cursor.getBlob(). It returns a byte array.

    If the table entry is a content: URI, you should never try to open and read the file directly (for one thing,
    permissions problems can make this fail). Instead, you should call ContentResolver.openInputStream()
    to get an InputStream object that you can use to read the data.


    Modifying Data

    Data kept by a content provider can be modified by:

   Adding new records
   Adding new values to existing records
   Batch updating existing records
   Deleting records

    All data modification is accomplished using ContentResolver methods. Some content providers require
    a more restrictive permission for writing data than they do for reading it. If you don't have permission to
    write to a content provider, the ContentResolver methods will fail.

    Adding records

    To add a new record to a content provider, first set up a map of key-value pairs in a ContentValues
    object, where each key matches the name of a column in the content provider and the value is the
    desired value for the new record in that column. Then call ContentResolver.insert() and pass it the URI
    of the provider and the ContentValues map. This method returns the full URI of the new record — that
    is, the provider's URI with the appended ID for the new record. You can then use this URI to query and
    get a Cursor over the new record, and to further modify the record. Here's an example:

      import android.provider.Contacts.People;
      import android.content.ContentResolver;
      import android.content.ContentValues;

      ContentValues values = new ContentValues();

      // Add Abraham Lincoln to contacts and make him a favorite.
      values.put(People.NAME, "Abraham Lincoln");
      // 1 = the new contact is added to favorites
      // 0 = the new contact is not added to favorites
      values.put(People.STARRED, 1);

      Uri uri = getContentResolver().insert(People.CONTENT_URI, values);


    Adding new values
Once a record exists, you can add new information to it or modify existing information. For example,
the next step in the example above would be to add contact information — like a phone number or an
IM or e-mail address — to the new entry.

The best way to add to a record in the Contacts database is to append the name of the table where the
new data goes to the URI for the record, then use the amended URI to add the new data values. Each
Contacts table exposes a name for this purpose as a CONTENT_DIRECTORY constant. The following
code continues the previous example by adding a phone number and e-mail address for the record
just created:

  Uri phoneUri = null;
  Uri emailUri = null;

  // Add a phone number for Abraham Lincoln. Begin with the URI for
  // the new record just returned by insert(); it ends with the _ID
  // of the new record, so we don't have to add the ID ourselves.
  // Then append the designation for the phone table to this URI,
  // and use the resulting URI to insert the phone number.
  phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);

  values.clear();
  values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
  values.put(People.Phones.NUMBER, "1233214567");
  getContentResolver().insert(phoneUri, values);

  // Now add an email address in the same way.
  emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);

  values.clear();
  // ContactMethods.KIND is used to distinguish different kinds of
  // contact methods, such as email, IM, etc.
  values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
  values.put(People.ContactMethods.DATA, "test@example.com");
  values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
  getContentResolver().insert(emailUri, values);


You can place small amounts of binary data into a table by calling the version of ContentValues.put()
that takes a byte array. That would work for a small icon-like image or a short audio clip, for example.
However, if you have a large amount of binary data to add, such as a photograph or a complete song,
put a content: URI for the data in the table and call ContentResolver.openOutputStream() with the file's
URI. (That causes the content provider to store the data in a file and record the file path in a hidden
field of the record.)

In this regard, the MediaStore content provider, the main provider that dispenses image, audio, and
video data, employs a special convention: The same URI that is used with query() or managedQuery()
to get meta-information about the binary data (such as, the caption of a photograph or the date it was
taken) is used with openInputStream() to get the data itself. Similarly, the same URI that is used with
insert() to put meta-information into a MediaStore record is used with openOutputStream() to place the
    binary data there. The following code snippet illustrates this convention:

      import android.provider.MediaStore.Images.Media;
      import android.content.ContentValues;
      import java.io.OutputStream;

      // Save the name and description of an image in a ContentValues map.
      ContentValues values = new ContentValues(3);
      values.put(Media.DISPLAY_NAME, "road_trip_1");
      values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
      values.put(Media.MIME_TYPE, "image/jpeg");

      // Add a new record without the bitmap, but with the values just set.
      // insert() returns the URI of the new record.
      Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);

      // Now get a handle to the file for that record, and save the data into it.
      // Here, sourceBitmap is a Bitmap object representing the file to save to the database.
      try {
         OutputStream outStream = getContentResolver().openOutputStream(uri);
         sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
         outStream.close();
      } catch (Exception e) {
         Log.e(TAG, "exception while writing image", e);
      }


    Batch updating records

    To batch update a group of records (for example, to change "NY" to "New York" in all fields), call the
    ContentResolver.update() method with the columns and values to change.

    Deleting a record

    To delete a single record, call {ContentResolver.delete() with the URI of a specific row.

    To delete multiple rows, call ContentResolver.delete() with the URI of the type of record to delete (for
    example, android.provider.Contacts.People.CONTENT_URI) and an SQL WHERE clause defining
    which rows to delete. (Caution: Be sure to include a valid WHERE clause if you're deleting a general
    type, or you risk deleting more records than you intended!).


    Creating a Content Provider

    To create a content provider, you must:

   Set up a system for storing the data. Most content providers store their data using Android's file
    storage methods or SQLite databases, but you can store your data any way you want. Android
provides the SQLiteOpenHelper class to help you create a database and SQLiteDatabase to manage
    it.
   Extend the ContentProvider class to provide access to the data.
   Declare the content provider in the manifest file for your application (AndroidManifest.xml).
    The following sections have notes on the last two of these tasks.

    Extending the ContentProvider class

    You define a ContentProvider subclass to expose your data to others using the conventions expected
    by ContentResolver and Cursor objects. Principally, this means implementing six abstract methods
    declared in the ContentProvider class:

        query()
        insert()
        update()
        delete()
        getType()
        onCreate()

    The query() method must return a Cursor object that can iterate over the requested data. Cursor itself
    is an interface, but Android provides some ready-made Cursor objects that you can use. For example,
    SQLiteCursor can iterate over data stored in an SQLite database. You get the Cursor object by calling
    any of the SQLiteDatabase class's query() methods. There are other Cursor implementations — such
    as MatrixCursor — for data not stored in a database.

    Because these ContentProvider methods can be called from various ContentResolver objects in
    different processes and threads, they must be implemented in a thread-safe manner.

    As a courtesy, you might also want to call ContentResolver.notifyChange() to notify listeners when
    there are modifications to the data.

    Beyond defining the subclass itself, there are other steps you should take to simplify the work of clients
    and make the class more accessible:

   Define a public static final Uri named CONTENT_URI. This is the string that represents the full content:
    URI that your content provider handles. You must define a unique string for this value. The best
    solution is to use the fully-qualified class name of the content provider (made lowercase). So, for
    example, the URI for a TransportationProvider class could be defined as follows:


      public static final Uri CONTENT_URI =
                Uri.parse("content://com.example.codelab.transportationprovider");

    If the provider has subtables, also define CONTENT_URI constants for each of the subtables. These
    URIs should all have the same authority (since that identifies the content provider), and be
    distinguished only by their paths. For example:
content://com.example.codelab.transportationprovider/train
        content://com.example.codelab.transportationprovider/air/domestic
        content://com.example.codelab.transportationprovider/air/international

    For an overview of content: URIs, see the Content URI Summary at the end of this document.

   Define the column names that the content provider will return to clients. If you are using an underlying
    database, these column names are typically identical to the SQL database column names they
    represent. Also define public static String constants that clients can use to specify the columns in
    queries and other instructions.
    Be sure to include an integer column named "_id" (with the constant _ID) for the IDs of the records.
    You should have this field whether or not you have another field (such as a URL) that is also unique
    among all records. If you're using the SQLite database, the _ID field should be the following type:

        INTEGER PRIMARY KEY AUTOINCREMENT

    The AUTOINCREMENT descriptor is optional. But without it, SQLite increments an ID counter field to
    the next number above the largest existing number in the column. If you delete the last row, the next
    row added will have the same ID as the deleted row. AUTOINCREMENT avoids this by having SQLite
    increment to the next largest value whether deleted or not.

   Carefully document the data type of each column. Clients need this information to read the data.
   If you are handling a new data type, you must define a new MIME type to return in your
    implementation of ContentProvider.getType(). The type depends in part on whether or not the content:
    URI submitted to getType() limits the request to a specific record. There's one form of the MIME type
    for a single record and another for multiple records. Use the Uri methods to help determine what is
    being requested. Here is the general format for each type:
o   For a single record:    vnd.android.cursor.item/vnd.yourcompanyname.contenttype
    For example, a request for train record 122, like this URI,

        content://com.example.transportationprovider/trains/122

    might return this MIME type:

        vnd.android.cursor.item/vnd.example.rail

o   For multiple records:    vnd.android.cursor.dir/vnd.yourcompanyname.contenttype
    For example, a request for all train records, like the following URI,

        content://com.example.transportationprovider/trains

    might return this MIME type:

        vnd.android.cursor.dir/vnd.example.rail

   If you are exposing byte data that's too big to put in the table itself — such as a large bitmap file — the
    field that exposes the data to clients should actually contain a content: URI string. This is the field that
    gives clients access to the data file. The record should also have another field, named "_data" that lists
the exact file path on the device for that file. This field is not intended to be read by the client, but by
the ContentResolver. The client will call ContentResolver.openInputStream() on the user-facing field
holding the URI for the item. The ContentResolver will request the "_data" field for that record, and
because it has higher permissions than a client, it should be able to access that file directly and return
a read wrapper for the file to the client.
For an example of a private content provider implementation, see the NodePadProvider class in the
Notepad sample application that ships with the SDK.

Declaring the content provider

To let the Android system know about the content provider you've developed, declare it with a
<provider> element in the application's AndroidManifest.xml file. Content providers that are not
declared in the manifest are not visible to the Android system

The name attribute is the fully qualified name of the ContentProvider subclass. The authorities attribute
is the authority part of the content: URI that identifies the provider. For example if the ContentProvider
subclass is AutoInfoProvider, the <provider> element might look like this:

  <provider android:name="com.example.autos.AutoInfoProvider"
        android:authorities="com.example.autos.autoinfoprovider"
        . . . />
  </provider>


Note that the authorities attribute omits the path part of a content: URI. For example, if
AutoInfoProvider controlled subtables for different types of autos or different manufacturers,

    content://com.example.autos.autoinfoprovider/honda
    content://com.example.autos.autoinfoprovider/gm/compact
    content://com.example.autos.autoinfoprovider/gm/suv

those paths would not be declared in the manifest. The authority is what identifies the provider, not the
path; your provider can interpret the path part of the URI in any way you choose.

Other <provider> attributes can set permissions to read and write data, provide for an icon and text
that can be displayed to users, enable and disable the provider, and so on. Set the multiprocess
attribute to "true" if data does not need to be synchronized between multiple running versions of the
content provider. This permits an instance of the provider to be created in each client process,
eliminating the need to perform IPC.


Content URI Summary

Here is a recap of the important parts of a content URI:
A. Standard prefix indicating that the data is controlled by a content provider. It's never modified.
B. The authority part of the URI; it identifies the content provider. For third-party applications, this should
   be a fully-qualified class name (reduced to lowercase) to ensure uniqueness. The authority is declared
   in the <provider> element's authorities attribute:

      <provider android:name=".TransportationProvider"
            android:authorities="com.example.transportationprovider"
            ... >

C. The path that the content provider uses to determine what kind of data is being requested. This can be
   zero or more segments long. If the content provider exposes only one type of data (only trains, for
   example), it can be absent. If the provider exposes several types, including subtypes, it can be several
   segments long — for example, "land/bus", "land/train", "sea/ship", and "sea/submarine" to give four
   possibilities.
D. The ID of the specific record being requested, if any. This is the _ID value of the requested record. If
   the request is not limited to a single record, this segment and the trailing slash are omitted:
        content://com.example.transportationprovider/trains

    Intent and intent filters.

    Three of the core components of an application — activities, services, and broadcast receivers — are
    activated through messages, called intents. Intent messaging is a facility for late run-time binding
    between components in the same or different applications. The intent itself, an Intent object, is a
    passive data structure holding an abstract description of an operation to be performed — or, often in
    the case of broadcasts, a description of something that has happened and is being announced. There
    are separate mechanisms for delivering intents to each type of component:

   An Intent object is passed to Context.startActivity() or Activity.startActivityForResult() to launch an
    activity or get an existing activity to do something new. (It can also be passed to Activity.setResult() to
    return information to the activity that called startActivityForResult().)
   An Intent object is passed to Context.startService() to initiate a service or deliver new instructions to an
    ongoing service. Similarly, an intent can be passed to Context.bindService() to establish a connection
    between the calling component and a target service. It can optionally initiate the service if it's not
    already running.
   Intent objects passed to any of the broadcast methods (such as Context.sendBroadcast(),
    Context.sendOrderedBroadcast(), or Context.sendStickyBroadcast()) are delivered to all interested
    broadcast receivers. Many kinds of broadcasts originate in system code.
    In each case, the Android system finds the appropriate activity, service, or set of broadcast receivers
    to respond to the intent, instantiating them if necessary. There is no overlap within these messaging
systems: Broadcast intents are delivered only to broadcast receivers, never to activities or services. An
intent passed to startActivity() is delivered only to an activity, never to a service or broadcast receiver,
and so on.

This document begins with a description of Intent objects. It then describes the rules Android uses to
map intents to components — how it resolves which component should receive an intent message. For
intents that don't explicitly name a target component, this process involves testing the Intent object
against intent filters associated with potential targets.


Intent Objects

An Intent object is a bundle of information. It contains information of interest to the component that
receives the intent (such as the action to be taken and the data to act on) plus information of interest to
the Android system (such as the category of component that should handle the intent and instructions
on how to launch a target activity). Principally, it can contain the following:

Component name

       The name of the component that should handle the intent. This field is a ComponentName
       object — a combination of the fully qualified class name of the target component (for example
       "com.example.project.app.FreneticActivity") and the package name set in the manifest file of the
       application where the component resides (for example, "com.example.project"). The package
       part of the component name and the package name set in the manifest do not necessarily have
       to match.

       The component name is optional. If it is set, the Intent object is delivered to an instance of the
       designated class. If it is not set, Android uses other information in the Intent object to locate a
       suitable target — see Intent Resolution, later in this document.

       The component name is set by setComponent(), setClass(), or setClassName() and read by
       getComponent().

Action

       A string naming the action to be performed — or, in the case of broadcast intents, the action
       that took place and is being reported. The Intent class defines a number of action constants,
       including these:


         Constant                                Target             Action
                                                 component


         ACTION_CALL                             activity           Initiate a phone call.
ACTION_EDIT                           activity           Display data for the user to edit.


         ACTION_MAIN                           activity           Start up as the initial activity of a task,
                                                                  with no data input and no returned
                                                                  output.


         ACTION_SYNC                           activity           Synchronize data on a server with
                                                                  data on the mobile device.


         ACTION_BATTERY_LOW                    broadcast          A warning that the battery is low.
                                               receiver


         ACTION_HEADSET_PLUG                   broadcast          A headset has been plugged into the
                                               receiver           device, or unplugged from it.


         ACTION_SCREEN_ON                      broadcast          The screen has been turned on.
                                               receiver


         ACTION_TIMEZONE_CHANGED               broadcast          The setting for the time zone has
                                               receiver           changed.


       See the Intent class description for a list of pre-defined constants for generic actions. Other
       actions are defined elsewhere in the Android API. You can also define your own action strings
       for activating the components in your application. Those you invent should include the
       application package as a prefix — for example: "com.example.project.SHOW_COLOR".

       The action largely determines how the rest of the intent is structured — particularly the data and
       extras fields — much as a method name determines a set of arguments and a return value. For
       this reason, it's a good idea to use action names that are as specific as possible, and to couple
       them tightly to the other fields of the intent. In other words, instead of defining an action in
       isolation, define an entire protocol for the Intent objects your components can handle.

       The action in an Intent object is set by the setAction() method and read by getAction().

Data

       The URI of the data to be acted on and the MIME type of that data. Different actions are paired
       with different kinds of data specifications. For example, if the action field is ACTION_EDIT, the
data field would contain the URI of the document to be displayed for editing. If the action is
     ACTION_CALL, the data field would be a tel: URI with the number to call. Similarly, if the action
     is ACTION_VIEW and the data field is an http: URI, the receiving activity would be called upon
     to download and display whatever data the URI refers to.

     When matching an intent to a component that is capable of handling the data, it's often
     important to know the type of data (its MIME type) in addition to its URI. For example, a
     component able to display image data should not be called upon to play an audio file.

     In many cases, the data type can be inferred from the URI — particularly content: URIs, which
     indicate that the data is located on the device and controlled by a content provider (see the
     separate discussion on content providers). But the type can also be explicitly set in the Intent
     object. The setData() method specifies data only as a URI, setType() specifies it only as a
     MIME type, and setDataAndType() specifies it as both a URI and a MIME type. The URI is read
     by getData() and the type by getType().

Category

     A string containing additional information about the kind of component that should handle the
     intent. Any number of category descriptions can be placed in an Intent object. As it does for
     actions, the Intent class defines several category constants, including these:


       Constant                         Meaning


       CATEGORY_BROWSABLE               The target activity can be safely invoked by the browser to
                                        display data referenced by a link — for example, an image or
                                        an e-mail message.


       CATEGORY_GADGET                  The activity can be embedded inside of another activity that
                                        hosts gadgets.


       CATEGORY_HOME                    The activity displays the home screen, the first screen the
                                        user sees when the device is turned on or when the HOME
                                        key is pressed.


       CATEGORY_LAUNCHER                The activity can be the initial activity of a task and is listed in
                                        the top-level application launcher.


       CATEGORY_PREFERENCE              The target activity is a preference panel.
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services
03 services

Mais conteúdo relacionado

Último

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 

Último (20)

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 

Destaque

Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 

Destaque (20)

Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 

03 services

  • 1. Services. A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background. A service can essentially take two forms: Started A service is "started" when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. For example, it might download or upload a file over the network. When the operation is done, the service should stop itself. Bound A service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed. Although this documentation generally discusses these two types of services separately, your service can work both ways—it can be started (to run indefinitely) and also allow binding. It's simply a matter of whether you implement a couple callback methods: onStartCommand() to allow components to start it and onBind() to allow binding. Regardless of whether your application is started, bound, or both, any application component can use the service (even from a separate application), in the same way that any component can use an activity—by starting it with an Intent. However, you can declare the service as private, in the manifest file, and block access from other applications. This is discussed more in the section about Declaring the service in the manifest. Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
  • 2. The Basics Should you use a service or a thread? A service is simply a component that can run in the background even when the user is not interacting with your application. Thus, you should create a service only if that is what you need. If you need to perform work outside your main thread, but only while the user is interacting with your application, then you should probably instead create a new thread and not a service. For example, if you want to play some music, but only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), then stop it in onStop(). Also consider using AsyncTask or HandlerThread, instead of the traditional Thread class. See the Processes and Threading document for more information about threads. Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations. To create a service, you must create a subclass of Service (or one of its existing subclasses). In your implementation, you need to override some callback methods that handle key aspects of the service lifecycle and provide a mechanism for components to bind to the service, if appropriate. The most important callback methods you should override are: onStartCommand() The system calls this method when another component, such as an activity, requests that the service be started, by calling startService(). Once this method executes, the service is started and can run in the background indefinitely. If you implement this, it is your responsibility to stop the service when its work is done, by calling stopSelf() or stopService(). (If you only want to provide binding, you don't need to implement this method.) onBind() The system calls this method when another component wants to bind with the service (such as to perform RPC), by calling bindService(). In your implementation of this method, you must provide an interface that clients use to communicate with the service, by returning an IBinder. You must always implement this method, but if you don't want to allow binding, then you should return null. onCreate() The system calls this method when the service is first created, to perform one-time setup procedures (before it calls either onStartCommand() or onBind()). If the service is already running, this method is not called. onDestroy() The system calls this method when the service is no longer used and is being destroyed. Your service should implement this to clean up any resources such as threads, registered listeners, receivers, etc. This is the last call the service receives.
  • 3. If a component starts the service by calling startService() (which results in a call to onStartCommand()), then the service remains running until it stops itself with stopSelf() or another component stops it by calling stopService(). If a component calls bindService() to create the service (and onStartCommand() is not called), then the service runs only as long as the component is bound to it. Once the service is unbound from all clients, the system destroys it. The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again (though this also depends on the value you return from onStartCommand(), as discussed later). For more information about when the system might destroy a service, see the Processes and Threading document. In the following sections, you'll see how you can create each type of service and how to use it from other application components. Declaring a service in the manifest Like activities (and other components), you must declare all services in your application's manifest file. To declare your service, add a <service> element as a child of the <application> element. For example: <manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest> There are other attributes you can include in the <service> element to define properties such as permissions required to start the service and the process in which the service should run. The android:name attribute is the only required attribute—it specifies the class name of the service. Once you publish your application, you should not change this name, because if you do, you might break some functionality where explicit intents are used to reference your service (read the blog post, Things That Cannot Change). See the <service> element reference for more information about declaring your service in the manifest.
  • 4. Just like an activity, a service can define intent filters that allow other components to invoke the service using implicit intents. By declaring intent filters, components from any application installed on the user's device can potentially start your service if your service declares an intent filter that matches the intent another application passes to startService(). If you plan on using your service only locally (other applications do not use it), then you don't need to (and should not) supply any intent filters. Without any intent filters, you must start the service using an intent that explicitly names the service class. More information about starting a service is discussed below. Additionally, you can ensure that your service is private to your application only if you include the android:exported attribute and set it to "false". This is effective even if your service supplies intent filters. For more information about creating intent filters for your service, see the Intents and Intent Filters document. Creating a Started Service Targeting Android 1.6 or lower If you're building an application for Android 1.6 or lower, you need to implement onStart(), instead of onStartCommand() (in Android 2.0, onStart() was deprecated in favor of onStartCommand()). For more information about providing compatibility with versions of Android older than 2.0, see the onStartCommand() documentation. A started service is one that another component starts by calling startService(), resulting in a call to the service's onStartCommand() method. When a service is started, it has a lifecycle that's independent of the component that started it and the service can run in the background indefinitely, even if the component that started it is destroyed. As such, the service should stop itself when its job is done by calling stopSelf(), or another component can stop it by calling stopService(). An application component such as an activity can start the service by calling startService() and passing an Intent that specifies the service and includes any data for the service to use. The service receives this Intent in the onStartCommand() method. For instance, suppose an activity needs to save some data to an online database. The activity can start a companion service and deliver it the data to save by passing an intent to startService(). The service receives the intent in onStartCommand(), connects to the Internet and performs the database transaction. When the transaction is done, the service stops itself and it is destroyed. Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow
  • 5. down activity performance. To avoid impacting application performance, you should start a new thread inside the service. Traditionally, there are two classes you can extend to create a started service: Service This is the base class for all services. When you extend this class, it's important that you create a new thread in which to do all the service's work, because the service uses your application's main thread, by default, which could slow the performance of any activity your application is running. IntentService This is a subclass of Service that uses a worker thread to handle all start requests, one at a time. This is the best option if you don't require that your service handle multiple requests simultaneously. All you need to do is implement onHandleIntent(), which receives the intent for each start request so you can do the background work. The following sections describe how you can implement your service using either one for these classes. Extending the IntentService class Because most started services don't need to handle multiple requests simultaneously (which can actually be a dangerous multi-threading scenario), it's probably best if you implement your service using the IntentService class. The IntentService does the following:  Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.  Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.  Stops the service after all start requests have been handled, so you never have to call stopSelf().  Provides default implementation of onBind() that returns null.  Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation. All this adds up to the fact that all you need to do is implement onHandleIntent() to do the work provided by the client. (Though, you also need to provide a small constructor for the service.) Here's an example implementation of IntentService: public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String)
  • 6. * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } } That's all you need: a constructor and an implementation of onHandleIntent(). If you decide to also override other callback methods, such as onCreate(), onStartCommand(), or onDestroy(), be sure to call the super implementation, so that the IntentService can properly handle the life of the worker thread. For example, onStartCommand() must return the default implementation (which is how the intent gets delivered to onHandleIntent()): @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); } Besides onHandleIntent(), the only method from which you don't need to call the super class is onBind() (but you only need to implement that if your service allows binding). In the next section, you'll see how the same kind of service is implemented when extending the base Service class, which is a lot more code, but which might be appropriate if you need to handle simultaneous start requests.
  • 7. Extending the Service class As you saw in the previous section, using IntentService makes your implementation of a started service very simple. If, however, you require your service to perform multi-threading (instead of processing start requests through a work queue), then you can extend the Service class to handle each intent. For comparison, the following example code is an implementation of the Service class that performs the exact same work as the example above using IntentService. That is, for each start request, it uses a worker thread to perform the job and processes only one request at a time. public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler
  • 8. mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } } As you can see, it's a lot more work than using IntentService. However, because you handle each call to onStartCommand() yourself, you can perform multiple requests simultaneously. That's not what this example does, but if that's what you want, then you can create a new thread for each request and run them right away (instead of waiting for the previous request to finish). Notice that the onStartCommand() method must return an integer. The integer is a value that describes how the system should continue the service in the event that the system kills it (as discussed above, the default implementation for IntentService handles this for you, though you are able to modify it). The return value from onStartCommand() must be one of the following constants: START_NOT_STICKY If the system kills the service after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs. START_STICKY
  • 9. If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job. START_REDELIVER_INTENT If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file. For more details about these return values, see the linked reference documentation for each constant. Starting a Service You can start a service from an activity or other application component by passing an Intent (specifying the service to start) to startService(). The Android system calls the service's onStartCommand() method and passes it the Intent. (You should never call onStartCommand() directly.) For example, an activity can start the example service in the previous section (HelloSevice) using an explicit intent with startService(): Intent intent = new Intent(this, HelloService.class); startService(intent); The startService() method returns immediately and the Android system calls the service's onStartCommand() method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand(). If the service does not also provide binding, the intent delivered with startService() is the only mode of communication between the application component and the service. However, if you want the service to send a result back, then the client that starts the service can create a PendingIntent for a broadcast (with getBroadcast()) and deliver it to the service in the Intent that starts the service. The service can then use the broadcast to deliver a result. Multiple requests to start the service result in multiple corresponding calls to the service's onStartCommand(). However, only one request to stop the service (with stopSelf() or stopService()) is required to stop it. Stopping a service A started service must manage its own lifecycle. That is, the system does not stop or destroy the service unless it must recover system memory and the service continues to run after onStartCommand() returns. So, the service must stop itself by calling stopSelf() or another component can stop it by calling stopService().
  • 10. Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as possible. However, if your service handles multiple requests to onStartCommand() concurrently, then you shouldn't stop the service when you're done processing a start request, because you might have since received a new start request (stopping at the end of the first request would terminate the second one). To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of the start request (the startId delivered to onStartCommand()) to which your stop request corresponds. Then if the service received a new start request before you were able to call stopSelf(int), then the ID will not match and the service will not stop. Caution: It's important that your application stops its services when it's done working, to avoid wasting system resources and consuming battery power. If necessary, other components can stop the service by calling stopService(). Even if you enable binding for the service, you must always stop the service yourself if it ever received a call to onStartCommand(). For more information about the lifecycle of a service, see the section below about Managing the Lifecycle of a Service. Creating a Bound Service A bound service is one that allows application components to bind to it by calling bindService() in order to create a long-standing connection (and generally does not allow components to start it by calling startService()). You should create a bound service when you want to interact with the service from activities and other components in your application or to expose some of your application's functionality to other applications, through interprocess communication (IPC). To create a bound service, you must implement the onBind() callback method to return an IBinder that defines the interface for communication with the service. Other application components can then call bindService() to retrieve the interface and begin calling methods on the service. The service lives only to serve the application component that is bound to it, so when there are no components bound to the service, the system destroys it (you do not need to stop a bound service in the way you must when the service is started through onStartCommand()). To create a bound service, the first thing you must do is define the interface that specifies how a client can communicate with the service. This interface between the service and a client must be an implementation of IBinder and is what your service must return from the onBind() callback method. Once the client receives the IBinder, it can begin interacting with the service through that interface. Multiple clients can bind to the service at once. When a client is done interacting with the service, it calls unbindService() to unbind. Once there are no clients bound to the service, the system destroys the service.
  • 11. There are multiple ways to implement a bound service and the implementation is more complicated than a started service, so the bound service discussion appears in a separate document about Bound Services. Sending Notifications to the User Once running, a service can notify the user of events using Toast Notifications or Status Bar Notifications. A toast notification is a message that appears on the surface of the current window for a moment then disappears, while a status bar notification provides an icon in the status bar with a message, which the user can select in order to take an action (such as start an activity). Usually, a status bar notification is the best technique when some background work has completed (such as a file completed downloading) and the user can now act on it. When the user selects the notification from the expanded view, the notification can start an activity (such as to view the downloaded file). See the Toast Notifications or Status Bar Notifications developer guides for more information. Running a Service in the Foreground A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground. For example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation. The notification in the status bar might indicate the current song and allow the user to launch an activity to interact with the music player. To request that your service run in the foreground, call startForeground(). This method takes two parameters: an integer that uniquely identifies the notification and the Notification for the status bar. For example: Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis()); Intent notificationIntent = new Intent(this, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION, notification); To remove the service from the foreground, call stopForeground(). This method takes a boolean, indicating whether to remove the status bar notification as well. This method does not stop the service.
  • 12. However, if you stop the service while it's still running in the foreground, then the notification is also removed. Note: The methods startForeground() and stopForeground() were introduced in Android 2.0 (API Level 5). In order to run your service in the foreground on older versions of the platform, you must use the previous setForeground() method—see the startForeground() documentation for information about how to provide backward compatibility. For more information about notifications, see Creating Status Bar Notifications. Managing the Lifecycle of a Service The lifecycle of a service is much simpler than that of an activity. However, it's even more important that you pay close attention to how your service is created and destroyed, because a service can run in the background without the user being aware. The service lifecycle—from when it's created to when it's destroyed—can follow two different paths:  A started service The service is created when another component calls startService(). The service then runs indefinitely and must stop itself by calling stopSelf(). Another component can also stop the service by calling stopService(). When the service is stopped, the system destroys it..  A bound service The service is created when another component (a client) calls bindService(). The client then communicates with the service through an IBinder interface. The client can close the connection by calling unbindService(). Multiple clients can bind to the same service and when all of them unbind, the system destroys the service. (The service does not need to stop itself.) These two paths are not entirely separate. That is, you can bind to a service that was already started with startService(). For example, a background music service could be started by calling startService() with an Intent that identifies the music to play. Later, possibly when the user wants to exercise some control over the player or get information about the current song, an activity can bind to the service by calling bindService(). In cases like this, stopService() or stopSelf() does not actually stop the service until all clients unbind. Implementing the lifecycle callbacks Like an activity, a service has lifecycle callback methods that you can implement to monitor changes in the service's state and perform work at the appropriate times. The following skeleton service demonstrates each of the lifecycle methods:
  • 13. Figure 2. The service lifecycle. The diagram on the left shows the lifecycle when the service is created with startService() and the diagram on the right shows the lifecycle when the service is created with bindService(). public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind; // indicates whether onRebind should be used @Override public void onCreate() { // The service is being created } @Override public int onStartCommand(Intent intent, int flags, int startId) { // The service is starting, due to a call to startService() return mStartMode; } @Override public IBinder onBind(Intent intent) { // A client is binding to the service with bindService() return mBinder; } @Override public boolean onUnbind(Intent intent) { // All clients have unbound with unbindService()
  • 14. return mAllowRebind; } @Override public void onRebind(Intent intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } @Override public void onDestroy() { // The service is no longer used and is being destroyed } } Note: Unlike the activity lifecycle callback methods, you are not required to call the superclass implementation of these callback methods. 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(), then stop the thread in onDestroy(). The onCreate() and onDestroy() methods are called for all services, whether they're created by startService() or bindService().  The active lifetime of a service begins with a call to either onStartCommand() or onBind(). Each method is handed the Intent that was passed to either startService() or bindService(), respectively. If the service is started, the active lifetime ends the same time that the entire lifetime ends (the service is still active even after onStartCommand() returns). If the service is bound, the active lifetime ends when onUnbind() returns. Note: Although a started service is stopped by a call to either stopSelf() or stopService(), there is not a respective callback for the service (there's no onStop() callback). So, unless the service is bound to a client, the system destroys it when the service is stopped—onDestroy() is the only callback received. Figure 2 illustrates the typical callback methods for a service. Although the figure separates services that are created by 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, a service that was initially started with onStartCommand() (by a client calling startService()) can still receive a call to onBind() (when a client calls bindService()). For more information about creating a service that provides binding, see the Bound Services document, which includes more information about the onRebind() callback method in the section about Managing the Lifecycle of a Bound Service.
  • 15. Bound Services. A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely. This document shows you how to create a bound service, including how to bind to the service from other application components. However, you should also refer to the Services document for additional information about services in general, such as how to deliver notifications from a service, set the service to run in the foreground, and more. The Basics A bound service is an implementation of the Service class that allows other applications to bind to it and interact with it. To provide binding for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming interface that clients can use to interact with the service. Binding to a Started Service As discussed in the Services document, you can create a service that is both started and bound. That is, the service can be started by calling startService(), which allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService(). If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service, by calling stopSelf() or stopService(). Although you should usually implement either onBind() or onStartCommand(), it's sometimes necessary to implement both. For example, a music player might find it useful to allow its service to run indefinitely and also provide binding. This way, an activity can start the service to play some music and the music continues to play even if the user leaves the application. Then, when the user returns to the application, the activity can bind to the service to regain control of playback. Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information about the service lifecycle when adding binding to a started service. A client can bind to the service by calling bindService(). When it does, it must provide an implementation of ServiceConnection, which monitors the connection with the service. The bindService() method returns immediately without a value, but when the Android system creates the connection between the client and service, it calls onServiceConnected() on the ServiceConnection, to deliver the IBinder that the client can use to communicate with the service. Multiple clients can connect to the service at once. However, the system calls your service's onBind() method to retrieve the IBinder only when the first client binds. The system then delivers the same IBinder to any additional clients that bind, without calling onBind() again.
  • 16. When the last client unbinds from the service, the system destroys the service (unless the service was also started by startService()). When you implement your bound service, the most important part is defining the interface that your onBind() callback method returns. There are a few different ways you can define your service's IBinder interface and the following section discusses each technique. Creating a Bound Service When creating a service that provides binding, you must provide an IBinder that provides the programming interface that clients can use to interact with the service. There are three ways you can define the interface: Extending the Binder class If your service is private to your own application and runs in the same process as the client (which is common), you should create your interface by extending the Binder class and returning an instance of it from onBind(). The client receives the Binder and can use it to directly access public methods available in either the Binder implementation or even the Service. This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes. Using a Messenger If you need your interface to work across different processes, you can create an interface for the service with a Messenger. In this manner, the service defines a Handler that responds to different types of Message objects. This Handler is the basis for a Messenger that can then share an IBinder with the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger of its own so the service can send messages back. This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don't have to design your service to be thread-safe. Using AIDL AIDL (Android Interface Definition Language) performs all the work to decompose objects into primitives that the operating system can understand and marshall them across processes to perform IPC. The previous technique, using a Messenger, is actually based on AIDL as its underlying structure. As mentioned above, the Messenger creates a queue of all the client requests in a single thread, so the service receives requests one at a time. If, however, you want your service to handle multiple requests simultaneously, then you can use AIDL directly. In this case, your service must be capable of multi-threading and be built thread-safe.
  • 17. To use AIDL directly, you must create an .aidl file that defines the programming interface. The Android SDK tools use this file to generate an abstract class that implements the interface and handles IPC, which you can then extend within your service. Note: Most applications should not use AIDL to create a bound service, because it may require multithreading capabilities and can result in a more complicated implementation. As such, AIDL is not suitable for most applications and this document does not discuss how to use it for your service. If you're certain that you need to use AIDL directly, see the AIDL document. Extending the Binder class If your service is used only by the local application and does not need to work across processes, then you can implement your own Binder class that provides your client direct access to public methods in the service. Note: This works only if the client and service are in the same application and process, which is most common. For example, this would work well for a music application that needs to bind an activity to its own service that's playing music in the background. Here's how to set it up: 1. In your service, create an instance of Binder that either: o contains public methods that the client can call o returns the current Service instance, which has public methods the client can call o or, returns an instance of another class hosted by the service with public methods the client can call 2. Return this instance of Binder from the onBind() callback method. 3. In the client, receive the Binder from the onServiceConnected() callback method and make calls to the bound service using the methods provided. Note: The reason the service and client must be in the same application is so the client can cast the returned object and properly call its APIs. The service and client must also be in the same process, because this technique does not perform any marshalling across processes. For example, here's a service that provides clients access to methods in the service through a Binder implementation: public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods
  • 18. return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } } The LocalBinder provides the getService() method for clients to retrieve the current instance of LocalService. This allows clients to call public methods in the service. For example, clients can call getRandomNumber() from the service. Here's an activity that binds to LocalService and calls getRandomNumber() when a button is clicked: public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance.
  • 19. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; } The above sample shows how the client binds to the service using an implementation of ServiceConnection and the onServiceConnected() callback. The next section provides more information about this process of binding to the service. Note: The example above doesn't explicitly unbind from the service, but all clients should unbind at an appropriate time (such as when the activity pauses). For more sample code, see the LocalService.java class and the LocalServiceActivities.java class in ApiDemos. Using a Messenger Compared to AIDL When you need to perform IPC, using a Messenger for your interface is simpler than implementing it with AIDL, because Messenger queues all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the service, which must then handle multi-threading. For most applications, the service doesn't need to perform multi-threading, so using a Messenger allows the service to handle one call at a time. If it's important that your service be multi-threaded, then you should use AIDL to define your interface. If you need your service to communicate with remote processes, then you can use a Messenger to provide the interface for your service. This technique allows you to perform interprocess communication (IPC) without the need to use AIDL. Here's a summary of how to use a Messenger:  The service implements a Handler that receives a callback for each call from a client.
  • 20. The Handler is used to create a Messenger object (which is a reference to the Handler).  The Messenger creates an IBinder that the service returns to clients from onBind().  Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.  The service receives each Message in its Handler—specifically, in the handleMessage() method. In this way, there are no "methods" for the client to call on the service. Instead, the client delivers "messages" (Message objects) that the service receives in its Handler. Here's a simple example service that uses a Messenger interface: public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } } Notice that the handleMessage() method in the Handler is where the service receives the incoming Message and decides what to do, based on the what member.
  • 21. All that a client needs to do is create a Messenger based on the IBinder returned by the service and send a message using send(). For example, here's a simple activity that binds to the service and delivers the MSG_SAY_HELLO message to the service: public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported 'what' value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }
  • 22. @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } } Notice that this example does not show how the service can respond to the client. If you want the service to respond, then you need to also create a Messenger in the client. Then when the client receives the onServiceConnected() callback, it sends a Message to the service that includes the client's Messenger in the replyTo parameter of the send() method. You can see an example of how to provide two-way messaging in the MessengerService.java (service) and MessengerServiceActivities.java (client) samples. Binding to a Service Application components (clients) can bind to a service by calling bindService(). The Android system then calls the service's onBind() method, which returns an IBinder for interacting with the service. The binding is asynchronous. bindService() returns immediately and does not return the IBinder to the client. To receive the IBinder, the client must create an instance of ServiceConnection and pass it to bindService(). The ServiceConnection includes a callback method that the system calls to deliver the IBinder. Note: Only activities, services, and content providers can bind to a service—you cannot bind to a service from a broadcast receiver. So, to bind to a service from your client, you must: 1. Implement ServiceConnection. Your implementation must override two callback methods: onServiceConnected() The system calls this to deliver the IBinder returned by the service's onBind() method.
  • 23. onServiceDisconnected() The Android system calls this when the connection to the service is unexpectedly lost, such as when the service has crashed or has been killed. This is not called when the client unbinds. 2. Call bindService(), passing the ServiceConnection implementation. 3. When the system calls your onServiceConnected() callback method, you can begin making calls to the service, using the methods defined by the interface. 4. To disconnect from the service, call unbindService(). When your client is destroyed, it will unbind from the service, but you should always unbind when you're done interacting with the service or when your activity pauses so that the service can shutdown while its not being used. (Appropriate times to bind and unbind is discussed more below.) For example, the following snippet connects the client to the service created above by extending the Binder class, so all it must do is cast the returned IBinder to the LocalService class and request the LocalService instance: LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } }; With this ServiceConnection, the client can bind to a service by passing this it to bindService(). For example: Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  The first parameter of bindService() is an Intent that explicitly names the service to bind (thought the intent could be implicit).  The second parameter is the ServiceConnection object.
  • 24. The third parameter is a flag indicating options for the binding. It should usually be BIND_AUTO_CREATE in order to create the service if its not already alive. Other possible values are BIND_DEBUG_UNBIND and BIND_NOT_FOREGROUND, or 0 for none. Additional notes Here are some important notes about binding to a service:  You should always trap DeadObjectException exceptions, which are thrown when the connection has broken. This is the only exception thrown by remote methods.  Objects are reference counted across processes.  You should usually pair the binding and unbinding during matching bring-up and tear-down moments of the client's lifecycle. For example: o If you only need to interact with the service while your activity is visible, you should bind during onStart() and unbind during onStop(). o If you want your activity to receive responses even while it is stopped in the background, then you can bind during onCreate() and unbind during onDestroy(). Beware that this implies that your activity needs to use the service the entire time it's running (even in the background), so if the service is in another process, then you increase the weight of the process and it becomes more likely that the system will kill it. Note: You should usually not bind and unbind during your activity's onResume() and onPause(), because these callbacks occur at every lifecycle transition and you should keep the processing that occurs at these transitions to a minimum. Also, if multiple activities in your application bind to the same service and there is a transition between two of those activities, the service may be destroyed and recreated as the current activity unbinds (during pause) before the next one binds (during resume). (This activity transition for how activities coordinate their lifecycles is described in the Activities document.) For more sample code, showing how to bind to a service, see the RemoteService.java class in ApiDemos.
  • 25. Managing the Lifecycle of a Bound Service Figure 1. The lifecycle for a service that is started and also allows binding. When a service is unbound from all clients, the Android system destroys it (unless it was also started with onStartCommand()). As such, you don't have to manage the lifecycle of your service if it's purely a bound service—the Android system manages it for you based on whether it is bound to any clients. However, if you choose to implement the onStartCommand() callback method, then you must explicitly stop the service, because the service is now considered to be started. In this case, the service runs until the service stops itself with stopSelf() or another component calls stopService(), regardless of whether it is bound to any clients. Additionally, if your service is started and accepts binding, then when the system calls your onUnbind() method, you can optionally return true if you would like to receive a call to onRebind() the next time a client binds to the service (instead of receiving a call to onBind()). onRebind() returns void, but the client still receives the IBinder in its onServiceConnected() callback. Below, figure 1 illustrates the logic for this kind of lifecycle. For more information about the lifecycle of an started service, see the Services document. Content Providers Content providers store and retrieve data and make it accessible to all applications. They're the only way to share data across applications; there's no common storage area that all Android packages can access. Android ships with a number of content providers for common data types (audio, video, images, personal contact information, and so on). You can see some of them listed in the android.provider package. You can query these providers for the data they contain (although, for some, you must acquire the proper permission to read the data).
  • 26. If you want to make your own data public, you have two options: You can create your own content provider (a ContentProvider subclass) or you can add the data to an existing provider — if there's one that controls the same type of data and you have permission to write to it. This document is an introduction to using content providers. After a brief discussion of the fundamentals, it explores how to query a content provider, how to modify data controlled by a provider, and how to create a content provider of your own. Content Provider Basics How a content provider actually stores its data under the covers is up to its designer. But all content providers implement a common interface for querying the provider and returning results — as well as for adding, altering, and deleting data. It's an interface that clients use indirectly, most generally through ContentResolver objects. You get a ContentResolver by calling getContentResolver() from within the implementation of an Activity or other application component: ContentResolver cr = getContentResolver(); You can then use the ContentResolver's methods to interact with whatever content providers you're interested in. When a query is initiated, the Android system identifies the content provider that's the target of the query and makes sure that it is up and running. The system instantiates all ContentProvider objects; you never need to do it on your own. In fact, you never deal directly with ContentProvider objects at all. Typically, there's just a single instance of each type of ContentProvider. But it can communicate with multiple ContentResolver objects in different applications and processes. The interaction between processes is handled by the ContentResolver and ContentProvider classes. The data model Content providers expose their data as a simple table on a database model, where each row is a record and each column is data of a particular type and meaning. For example, information about people and their phone numbers might be exposed as follows: _ID NUMBER NUMBER_KEY LABEL NAME TYPE 13 (425) 555 6677 425 555 6677 Kirkland office Bully Pulpit TYPE_WORK 44 (212) 555-1234 212 555 1234 NY apartment Alan Vain TYPE_HOME 45 (212) 555-6657 212 555 6657 Downtown office Alan Vain TYPE_MOBILE 53 201.555.4433 201 555 4433 Love Nest Rex Cars TYPE_HOME
  • 27. Every record includes a numeric _ID field that uniquely identifies the record within the table. IDs can be used to match records in related tables — for example, to find a person's phone number in one table and pictures of that person in another. A query returns a Cursor object that can move from record to record and column to column to read the contents of each field. It has specialized methods for reading each type of data. So, to read a field, you must know what type of data the field contains. (There's more on query results and Cursor objects later.) URIs Each content provider exposes a public URI (wrapped as a Uri object) that uniquely identifies its data set. A content provider that controls multiple data sets (multiple tables) exposes a separate URI for each one. All URIs for providers begin with the string "content://". The content: scheme identifies the data as being controlled by a content provider. If you're defining a content provider, it's a good idea to also define a constant for its URI, to simplify client code and make future updates cleaner. Android defines CONTENT_URI constants for all the providers that come with the platform. For example, the URI for the table that matches phone numbers to people and the URI for the table that holds pictures of people (both controlled by the Contacts content provider) are: android.provider.Contacts.Phones.CONTENT_URI android.provider.Contacts.Photos.CONTENT_URI The URI constant is used in all interactions with the content provider. Every ContentResolver method takes the URI as its first argument. It's what identifies which provider the ContentResolver should talk to and which table of the provider is being targeted. Querying a Content Provider You need three pieces of information to query a content provider:  The URI that identifies the provider  The names of the data fields you want to receive  The data types for those fields If you're querying a particular record, you also need the ID for that record. Making the query To query a content provider, you can use either the ContentResolver.query() method or the Activity.managedQuery() method. Both methods take the same set of arguments, and both return a Cursor object. However, managedQuery() causes the activity to manage the life cycle of the Cursor. A managed Cursor handles all of the niceties, such as unloading itself when the activity pauses, and
  • 28. requerying itself when the activity restarts. You can ask an Activity to begin managing an unmanaged Cursor object for you by calling Activity.startManagingCursor(). The first argument to either query() or managedQuery() is the provider URI — the CONTENT_URI constant that identifies a particular ContentProvider and data set (see URIs earlier). To restrict a query to just one record, you can append the _ID value for that record to the URI — that is, place a string matching the ID as the last segment of the path part of the URI. For example, if the ID is 23, the URI would be: content://. . . ./23 There are some helper methods, particularly ContentUris.withAppendedId() and Uri.withAppendedPath(), that make it easy to append an ID to a URI. Both are static methods that return a Uri object with the ID added. So, for example, if you were looking for record 23 in the database of people contacts, you might construct a query as follows: import android.provider.Contacts.People; import android.content.ContentUris; import android.net.Uri; import android.database.Cursor; // Use the ContentUris method to produce the base URI for the contact with _ID == 23. Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23); // Alternatively, use the Uri method to produce the base URI. // It takes a string rather than an integer. Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23"); // Then query for this specific record: Cursor cur = managedQuery(myPerson, null, null, null, null); The other arguments to the query() and managedQuery() methods delimit the query in more detail. They are:  The names of the data columns that should be returned. A null value returns all columns. Otherwise, only columns that are listed by name are returned. All the content providers that come with the platform define constants for their columns. For example, the android.provider.Contacts.Phones class defines constants for the names of the columns in the phone table illustrated earlier &mdash _ID, NUMBER, NUMBER_KEY, NAME, and so on.  A filter detailing which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). A null value returns all rows (unless the URI limits the query to a single record).  Selection arguments.  A sorting order for the rows that are returned, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). A null value returns the records in the default order for the table, which may be unordered.
  • 29. Let's look at an example query to retrieve a list of contact names and their primary phone numbers: import android.provider.Contacts.People; import android.database.Cursor; // Form an array specifying which columns to return. String[] projection = new String[] { People._ID, People._COUNT, People.NAME, People.NUMBER }; // Get the base URI for the People table in the Contacts content provider. Uri contacts = People.CONTENT_URI; // Make the query. Cursor managedCursor = managedQuery(contacts, projection, // Which columns to return null, // Which rows to return (all rows) null, // Selection arguments (none) // Put the results in ascending order by name People.NAME + " ASC"); This query retrieves data from the People table of the Contacts content provider. It gets the name, primary phone number, and unique record ID for each contact. It also reports the number of records that are returned as the _COUNT field of each record. The constants for the names of the columns are defined in various interfaces — _ID and _COUNT in BaseColumns, NAME in PeopleColumns, and NUMBER in PhoneColumns. The Contacts.People class implements each of these interfaces, which is why the code example above could refer to them using just the class name. What a query returns A query returns a set of zero or more database records. The names of the columns, their default order, and their data types are specific to each content provider. But every provider has an _ID column, which holds a unique numeric ID for each record. Every provider can also report the number of records returned as the _COUNT column; its value is the same for all rows. Here is an example result set for the query in the previous section: _ID _COUNT NAME NUMBER 44 3 Alan Vain 212 555 1234
  • 30. 13 3 Bully Pulpit 425 555 6677 53 3 Rex Cars 201 555 4433 The retrieved data is exposed by a Cursor object that can be used to iterate backward or forward through the result set. You can use this object only to read the data. To add, modify, or delete data, you must use a ContentResolver object. Reading retrieved data The Cursor object returned by a query provides access to a recordset of results. If you have queried for a specific record by ID, this set will contain only one value. Otherwise, it can contain multiple values. (If there are no matches, it can also be empty.) You can read data from specific fields in the record, but you must know the data type of the field, because the Cursor object has a separate method for reading each type of data — such as getString(), getInt(), and getFloat(). (However, for most types, if you call the method for reading strings, the Cursor object will give you the String representation of the data.) The Cursor lets you request the column name from the index of the column, or the index number from the column name. The following snippet demonstrates reading names and phone numbers from the query illustrated earlier: import android.provider.Contacts.People; private void getColumnData(Cursor cur){ if (cur.moveToFirst()) { String name; String phoneNumber; int nameColumn = cur.getColumnIndex(People.NAME); int phoneColumn = cur.getColumnIndex(People.NUMBER); String imagePath; do { // Get the field values name = cur.getString(nameColumn); phoneNumber = cur.getString(phoneColumn); // Do something with the values. ... } while (cur.moveToNext()); } }
  • 31. If a query can return binary data, such as an image or sound, the data may be directly entered in the table or the table entry for that data may be a string specifying a content: URI that you can use to get the data. In general, smaller amounts of data (say, from 20 to 50K or less) are most often directly entered in the table and can be read by calling Cursor.getBlob(). It returns a byte array. If the table entry is a content: URI, you should never try to open and read the file directly (for one thing, permissions problems can make this fail). Instead, you should call ContentResolver.openInputStream() to get an InputStream object that you can use to read the data. Modifying Data Data kept by a content provider can be modified by:  Adding new records  Adding new values to existing records  Batch updating existing records  Deleting records All data modification is accomplished using ContentResolver methods. Some content providers require a more restrictive permission for writing data than they do for reading it. If you don't have permission to write to a content provider, the ContentResolver methods will fail. Adding records To add a new record to a content provider, first set up a map of key-value pairs in a ContentValues object, where each key matches the name of a column in the content provider and the value is the desired value for the new record in that column. Then call ContentResolver.insert() and pass it the URI of the provider and the ContentValues map. This method returns the full URI of the new record — that is, the provider's URI with the appended ID for the new record. You can then use this URI to query and get a Cursor over the new record, and to further modify the record. Here's an example: import android.provider.Contacts.People; import android.content.ContentResolver; import android.content.ContentValues; ContentValues values = new ContentValues(); // Add Abraham Lincoln to contacts and make him a favorite. values.put(People.NAME, "Abraham Lincoln"); // 1 = the new contact is added to favorites // 0 = the new contact is not added to favorites values.put(People.STARRED, 1); Uri uri = getContentResolver().insert(People.CONTENT_URI, values); Adding new values
  • 32. Once a record exists, you can add new information to it or modify existing information. For example, the next step in the example above would be to add contact information — like a phone number or an IM or e-mail address — to the new entry. The best way to add to a record in the Contacts database is to append the name of the table where the new data goes to the URI for the record, then use the amended URI to add the new data values. Each Contacts table exposes a name for this purpose as a CONTENT_DIRECTORY constant. The following code continues the previous example by adding a phone number and e-mail address for the record just created: Uri phoneUri = null; Uri emailUri = null; // Add a phone number for Abraham Lincoln. Begin with the URI for // the new record just returned by insert(); it ends with the _ID // of the new record, so we don't have to add the ID ourselves. // Then append the designation for the phone table to this URI, // and use the resulting URI to insert the phone number. phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); values.clear(); values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE); values.put(People.Phones.NUMBER, "1233214567"); getContentResolver().insert(phoneUri, values); // Now add an email address in the same way. emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY); values.clear(); // ContactMethods.KIND is used to distinguish different kinds of // contact methods, such as email, IM, etc. values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL); values.put(People.ContactMethods.DATA, "test@example.com"); values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME); getContentResolver().insert(emailUri, values); You can place small amounts of binary data into a table by calling the version of ContentValues.put() that takes a byte array. That would work for a small icon-like image or a short audio clip, for example. However, if you have a large amount of binary data to add, such as a photograph or a complete song, put a content: URI for the data in the table and call ContentResolver.openOutputStream() with the file's URI. (That causes the content provider to store the data in a file and record the file path in a hidden field of the record.) In this regard, the MediaStore content provider, the main provider that dispenses image, audio, and video data, employs a special convention: The same URI that is used with query() or managedQuery() to get meta-information about the binary data (such as, the caption of a photograph or the date it was taken) is used with openInputStream() to get the data itself. Similarly, the same URI that is used with
  • 33. insert() to put meta-information into a MediaStore record is used with openOutputStream() to place the binary data there. The following code snippet illustrates this convention: import android.provider.MediaStore.Images.Media; import android.content.ContentValues; import java.io.OutputStream; // Save the name and description of an image in a ContentValues map. ContentValues values = new ContentValues(3); values.put(Media.DISPLAY_NAME, "road_trip_1"); values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles"); values.put(Media.MIME_TYPE, "image/jpeg"); // Add a new record without the bitmap, but with the values just set. // insert() returns the URI of the new record. Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values); // Now get a handle to the file for that record, and save the data into it. // Here, sourceBitmap is a Bitmap object representing the file to save to the database. try { OutputStream outStream = getContentResolver().openOutputStream(uri); sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream); outStream.close(); } catch (Exception e) { Log.e(TAG, "exception while writing image", e); } Batch updating records To batch update a group of records (for example, to change "NY" to "New York" in all fields), call the ContentResolver.update() method with the columns and values to change. Deleting a record To delete a single record, call {ContentResolver.delete() with the URI of a specific row. To delete multiple rows, call ContentResolver.delete() with the URI of the type of record to delete (for example, android.provider.Contacts.People.CONTENT_URI) and an SQL WHERE clause defining which rows to delete. (Caution: Be sure to include a valid WHERE clause if you're deleting a general type, or you risk deleting more records than you intended!). Creating a Content Provider To create a content provider, you must:  Set up a system for storing the data. Most content providers store their data using Android's file storage methods or SQLite databases, but you can store your data any way you want. Android
  • 34. provides the SQLiteOpenHelper class to help you create a database and SQLiteDatabase to manage it.  Extend the ContentProvider class to provide access to the data.  Declare the content provider in the manifest file for your application (AndroidManifest.xml). The following sections have notes on the last two of these tasks. Extending the ContentProvider class You define a ContentProvider subclass to expose your data to others using the conventions expected by ContentResolver and Cursor objects. Principally, this means implementing six abstract methods declared in the ContentProvider class: query() insert() update() delete() getType() onCreate() The query() method must return a Cursor object that can iterate over the requested data. Cursor itself is an interface, but Android provides some ready-made Cursor objects that you can use. For example, SQLiteCursor can iterate over data stored in an SQLite database. You get the Cursor object by calling any of the SQLiteDatabase class's query() methods. There are other Cursor implementations — such as MatrixCursor — for data not stored in a database. Because these ContentProvider methods can be called from various ContentResolver objects in different processes and threads, they must be implemented in a thread-safe manner. As a courtesy, you might also want to call ContentResolver.notifyChange() to notify listeners when there are modifications to the data. Beyond defining the subclass itself, there are other steps you should take to simplify the work of clients and make the class more accessible:  Define a public static final Uri named CONTENT_URI. This is the string that represents the full content: URI that your content provider handles. You must define a unique string for this value. The best solution is to use the fully-qualified class name of the content provider (made lowercase). So, for example, the URI for a TransportationProvider class could be defined as follows: public static final Uri CONTENT_URI = Uri.parse("content://com.example.codelab.transportationprovider"); If the provider has subtables, also define CONTENT_URI constants for each of the subtables. These URIs should all have the same authority (since that identifies the content provider), and be distinguished only by their paths. For example:
  • 35. content://com.example.codelab.transportationprovider/train content://com.example.codelab.transportationprovider/air/domestic content://com.example.codelab.transportationprovider/air/international For an overview of content: URIs, see the Content URI Summary at the end of this document.  Define the column names that the content provider will return to clients. If you are using an underlying database, these column names are typically identical to the SQL database column names they represent. Also define public static String constants that clients can use to specify the columns in queries and other instructions. Be sure to include an integer column named "_id" (with the constant _ID) for the IDs of the records. You should have this field whether or not you have another field (such as a URL) that is also unique among all records. If you're using the SQLite database, the _ID field should be the following type: INTEGER PRIMARY KEY AUTOINCREMENT The AUTOINCREMENT descriptor is optional. But without it, SQLite increments an ID counter field to the next number above the largest existing number in the column. If you delete the last row, the next row added will have the same ID as the deleted row. AUTOINCREMENT avoids this by having SQLite increment to the next largest value whether deleted or not.  Carefully document the data type of each column. Clients need this information to read the data.  If you are handling a new data type, you must define a new MIME type to return in your implementation of ContentProvider.getType(). The type depends in part on whether or not the content: URI submitted to getType() limits the request to a specific record. There's one form of the MIME type for a single record and another for multiple records. Use the Uri methods to help determine what is being requested. Here is the general format for each type: o For a single record: vnd.android.cursor.item/vnd.yourcompanyname.contenttype For example, a request for train record 122, like this URI, content://com.example.transportationprovider/trains/122 might return this MIME type: vnd.android.cursor.item/vnd.example.rail o For multiple records: vnd.android.cursor.dir/vnd.yourcompanyname.contenttype For example, a request for all train records, like the following URI, content://com.example.transportationprovider/trains might return this MIME type: vnd.android.cursor.dir/vnd.example.rail  If you are exposing byte data that's too big to put in the table itself — such as a large bitmap file — the field that exposes the data to clients should actually contain a content: URI string. This is the field that gives clients access to the data file. The record should also have another field, named "_data" that lists
  • 36. the exact file path on the device for that file. This field is not intended to be read by the client, but by the ContentResolver. The client will call ContentResolver.openInputStream() on the user-facing field holding the URI for the item. The ContentResolver will request the "_data" field for that record, and because it has higher permissions than a client, it should be able to access that file directly and return a read wrapper for the file to the client. For an example of a private content provider implementation, see the NodePadProvider class in the Notepad sample application that ships with the SDK. Declaring the content provider To let the Android system know about the content provider you've developed, declare it with a <provider> element in the application's AndroidManifest.xml file. Content providers that are not declared in the manifest are not visible to the Android system The name attribute is the fully qualified name of the ContentProvider subclass. The authorities attribute is the authority part of the content: URI that identifies the provider. For example if the ContentProvider subclass is AutoInfoProvider, the <provider> element might look like this: <provider android:name="com.example.autos.AutoInfoProvider" android:authorities="com.example.autos.autoinfoprovider" . . . /> </provider> Note that the authorities attribute omits the path part of a content: URI. For example, if AutoInfoProvider controlled subtables for different types of autos or different manufacturers, content://com.example.autos.autoinfoprovider/honda content://com.example.autos.autoinfoprovider/gm/compact content://com.example.autos.autoinfoprovider/gm/suv those paths would not be declared in the manifest. The authority is what identifies the provider, not the path; your provider can interpret the path part of the URI in any way you choose. Other <provider> attributes can set permissions to read and write data, provide for an icon and text that can be displayed to users, enable and disable the provider, and so on. Set the multiprocess attribute to "true" if data does not need to be synchronized between multiple running versions of the content provider. This permits an instance of the provider to be created in each client process, eliminating the need to perform IPC. Content URI Summary Here is a recap of the important parts of a content URI:
  • 37. A. Standard prefix indicating that the data is controlled by a content provider. It's never modified. B. The authority part of the URI; it identifies the content provider. For third-party applications, this should be a fully-qualified class name (reduced to lowercase) to ensure uniqueness. The authority is declared in the <provider> element's authorities attribute: <provider android:name=".TransportationProvider" android:authorities="com.example.transportationprovider" ... > C. The path that the content provider uses to determine what kind of data is being requested. This can be zero or more segments long. If the content provider exposes only one type of data (only trains, for example), it can be absent. If the provider exposes several types, including subtypes, it can be several segments long — for example, "land/bus", "land/train", "sea/ship", and "sea/submarine" to give four possibilities. D. The ID of the specific record being requested, if any. This is the _ID value of the requested record. If the request is not limited to a single record, this segment and the trailing slash are omitted: content://com.example.transportationprovider/trains Intent and intent filters. Three of the core components of an application — activities, services, and broadcast receivers — are activated through messages, called intents. Intent messaging is a facility for late run-time binding between components in the same or different applications. The intent itself, an Intent object, is a passive data structure holding an abstract description of an operation to be performed — or, often in the case of broadcasts, a description of something that has happened and is being announced. There are separate mechanisms for delivering intents to each type of component:  An Intent object is passed to Context.startActivity() or Activity.startActivityForResult() to launch an activity or get an existing activity to do something new. (It can also be passed to Activity.setResult() to return information to the activity that called startActivityForResult().)  An Intent object is passed to Context.startService() to initiate a service or deliver new instructions to an ongoing service. Similarly, an intent can be passed to Context.bindService() to establish a connection between the calling component and a target service. It can optionally initiate the service if it's not already running.  Intent objects passed to any of the broadcast methods (such as Context.sendBroadcast(), Context.sendOrderedBroadcast(), or Context.sendStickyBroadcast()) are delivered to all interested broadcast receivers. Many kinds of broadcasts originate in system code. In each case, the Android system finds the appropriate activity, service, or set of broadcast receivers to respond to the intent, instantiating them if necessary. There is no overlap within these messaging
  • 38. systems: Broadcast intents are delivered only to broadcast receivers, never to activities or services. An intent passed to startActivity() is delivered only to an activity, never to a service or broadcast receiver, and so on. This document begins with a description of Intent objects. It then describes the rules Android uses to map intents to components — how it resolves which component should receive an intent message. For intents that don't explicitly name a target component, this process involves testing the Intent object against intent filters associated with potential targets. Intent Objects An Intent object is a bundle of information. It contains information of interest to the component that receives the intent (such as the action to be taken and the data to act on) plus information of interest to the Android system (such as the category of component that should handle the intent and instructions on how to launch a target activity). Principally, it can contain the following: Component name The name of the component that should handle the intent. This field is a ComponentName object — a combination of the fully qualified class name of the target component (for example "com.example.project.app.FreneticActivity") and the package name set in the manifest file of the application where the component resides (for example, "com.example.project"). The package part of the component name and the package name set in the manifest do not necessarily have to match. The component name is optional. If it is set, the Intent object is delivered to an instance of the designated class. If it is not set, Android uses other information in the Intent object to locate a suitable target — see Intent Resolution, later in this document. The component name is set by setComponent(), setClass(), or setClassName() and read by getComponent(). Action A string naming the action to be performed — or, in the case of broadcast intents, the action that took place and is being reported. The Intent class defines a number of action constants, including these: Constant Target Action component ACTION_CALL activity Initiate a phone call.
  • 39. ACTION_EDIT activity Display data for the user to edit. ACTION_MAIN activity Start up as the initial activity of a task, with no data input and no returned output. ACTION_SYNC activity Synchronize data on a server with data on the mobile device. ACTION_BATTERY_LOW broadcast A warning that the battery is low. receiver ACTION_HEADSET_PLUG broadcast A headset has been plugged into the receiver device, or unplugged from it. ACTION_SCREEN_ON broadcast The screen has been turned on. receiver ACTION_TIMEZONE_CHANGED broadcast The setting for the time zone has receiver changed. See the Intent class description for a list of pre-defined constants for generic actions. Other actions are defined elsewhere in the Android API. You can also define your own action strings for activating the components in your application. Those you invent should include the application package as a prefix — for example: "com.example.project.SHOW_COLOR". The action largely determines how the rest of the intent is structured — particularly the data and extras fields — much as a method name determines a set of arguments and a return value. For this reason, it's a good idea to use action names that are as specific as possible, and to couple them tightly to the other fields of the intent. In other words, instead of defining an action in isolation, define an entire protocol for the Intent objects your components can handle. The action in an Intent object is set by the setAction() method and read by getAction(). Data The URI of the data to be acted on and the MIME type of that data. Different actions are paired with different kinds of data specifications. For example, if the action field is ACTION_EDIT, the
  • 40. data field would contain the URI of the document to be displayed for editing. If the action is ACTION_CALL, the data field would be a tel: URI with the number to call. Similarly, if the action is ACTION_VIEW and the data field is an http: URI, the receiving activity would be called upon to download and display whatever data the URI refers to. When matching an intent to a component that is capable of handling the data, it's often important to know the type of data (its MIME type) in addition to its URI. For example, a component able to display image data should not be called upon to play an audio file. In many cases, the data type can be inferred from the URI — particularly content: URIs, which indicate that the data is located on the device and controlled by a content provider (see the separate discussion on content providers). But the type can also be explicitly set in the Intent object. The setData() method specifies data only as a URI, setType() specifies it only as a MIME type, and setDataAndType() specifies it as both a URI and a MIME type. The URI is read by getData() and the type by getType(). Category A string containing additional information about the kind of component that should handle the intent. Any number of category descriptions can be placed in an Intent object. As it does for actions, the Intent class defines several category constants, including these: Constant Meaning CATEGORY_BROWSABLE The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message. CATEGORY_GADGET The activity can be embedded inside of another activity that hosts gadgets. CATEGORY_HOME The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed. CATEGORY_LAUNCHER The activity can be the initial activity of a task and is listed in the top-level application launcher. CATEGORY_PREFERENCE The target activity is a preference panel.