MY mENU


Wednesday 4 April 2012

Services in Android


Services are described by subclasses of the abstract android.app.Service class, which is an indirect subclass of Context. Service subclasses override various Service lifecycle callback methods that Android
calls during the life of a service. For example, the SimpleService class in Listing 1–4 extends Service and also overrides the void onCreate() and void onDestroy() lifecycle callback methods.

Listing 1–4.

import android.app.Service;
public class SimpleService extends Service
{
@Override
public void onCreate()
{
System.out.println("onCreate() called");
}
@Override
public void onDestroy()
{

System.out.println("onDestroy() called");
}
@Override
public IBinder onBind(Intent intent)
{
System.out.println("onBind(Intent) never called");
return null;
}
}

onCreate() is called when the service is initially created, and onDestroy() is called when the service is being removed. Because it is abstract, the IBinder onBind(Intent intent) lifecycle callback method (described later in this section) must always be overridden, even if only to return null, which indicates that this method is ignored.

NOTE: Service subclasses typically override onCreate() and onDestroy() to perform initialization and cleanup. Unlike Activity’s onCreate(Bundle) and onDestroy() methods, Service’s onCreate() method isn’t repeatedly called and its onDestroy() method is always called.

A service’s lifetime happens between the time onCreate() is called and the time onDestroy() returns. As with an activity, a service initializes in onCreate() and cleans up in onDestroy(). For example, a music playback service could create the thread that plays music in onCreate() and stop the thread in onDestroy().

Local services: are typically started via Context’s ComponentName startService(Intent intent) method, which returns an android.content.ComponentName instance that identifies the started service component, or the null reference if the service doesn’t exist. Furthermore, startService(Intent) results in the lifecycle shown in Figure 1–4.

The lifecycle of a service that’s started by startService(Intent) features a call to onStartCommand(Intent, int, int). The call to startService(Intent) results in a call to onCreate(), followed by a call to int onStartCommand(Intent intent, int flags, int startId). This latter lifecycle callback method, which replaces the deprecated void onStart(Intent intent, int startId) method, is called with the following arguments:
􀀁 intent is the Intent object passed to startService(Intent).
􀀁 flags can provide additional data about the start request, but are often set to 0.
􀀁 startID is a unique integer that describes this start request. A service can pass this value to Service’s boolean stopSelfResult(int startId) method to stop itself.


onStartCommand(Intent, int, int) processes the Intent object, and typically returns the constant Service.START_STICKY to indicate that the service is to continue running until explicitly stopped. At this point, the service is running and will continue to run until one of the following events occurs:
􀀁 Another component stops the service by calling Context’s boolean stopService(Intent intent) method. Only one stopService(Intent) call is needed no matter how often startService(Intent) was called.
􀀁 The service stops itself by calling one of Service’s overloaded stopSelf() methods, or by calling Service’s stopSelfResult(int) method.

After stopService(Intent), stopSelf(), or stopSelfResult(int) has been called, Android calls onDestroy() to let the service perform cleanup tasks.

NOTE: When a service is started by calling startService(Intent), onBind(Intent) is not called.

Listing 1–5 presents a skeletal service class that could be used in the context of the startService(Intent) method.
Listing 1–5. 

import android.app.Service;
public class SimpleService extends Service
{
@Override
public void onCreate()
{
System.out.println("onCreate() called");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
System.out.println("onStartCommand(Intent, int, int) called");
return START_STICKY;
}
@Override
public void onDestroy()
{
System.out.println("onDestroy() called");
}

@Override
public IBinder onBind(Intent intent)
{
System.out.println("onBind(Intent) never called");
return null;
}
}

The following code fragment, which is assumed to be located in the onCreate() method of Listing 1–2’s SimpleActivity class, employs startService(Intent) to start an instance of Listing 1–5’s SimpleService class via an explicit intent:

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

Remote services :are started via Context’s boolean bindService(Intent service, ServiceConnection conn, int flags) method, which connects to a running service, creating the service if necessary, and which returns ‘true’ when successfully connected. bindService(Intent, ServiceConnection, int) results in the lifecycle illustrated by
Figure 1–5.


Figure 1–5. The lifecycle of a service started by bindService(Intent, ServiceConnection, int) doesn’t
include a call to onStartCommand(Intent, int, int). The call to bindService(Intent, ServiceConnection, int) results in a call to onCreate() followed by a call to onBind(Intent), which returns the communications
channel (an instance of a class that implements the android.os.IBinder interface) that clients use to interact with the service.

The client interacts with the service as follows:
1. The client subclasses android.content.ServiceConnection and overrides this class’s abstract void onServiceConnected(ComponentName className, IBinder service) and void onServiceDisconnected(ComponentName name) methods in order to receive information about the service as the service is started and stopped. When bindService(Intent, ServiceConnection, int) returns true, the former method is called when a connection to the service has been established; the IBinder argument passed to this method is the same value returned from onBind(Intent). The latter method is called when a connection to the service has been lost. Lost connections typically occur when the process hosting the service has crashed or has been killed. The ServiceConnection instance itself is not removed
– the binding to the service will remain active, and the client will receive a call to onServiceConnected(ComponentName, IBinder) when the service is next running.

2.  The client passes the ServiceConnection subclass object to bindService(Intent, ServiceConnection, int). 

A client disconnects from a service by calling Context’s void unbindService(ServiceConnection conn) method.  This component no longer receives calls as the service is restarted. If no other components are bound to the service, the service is allowed to stop at any time. Before the service can stop, Android calls the service’s boolean onUnbind(Intent intent) lifecycle callback method with the Intent object that was passed to unbindService(ServiceConnection). Assuming that onUnbind(Intent) doesn’t return ‘true,’ which tells Android to call the service’s void onRebind(Intent intent) lifecycle callback method each time a client subsequently binds to the service, Android calls
onDestroy() to destroy the service.

Listing 1–6 presents a skeletal service class that could be used in the context of the bindService(Intent, ServiceConnection, int) method.
Listing 1–6.


import android.app.Service;
public class SimpleService extends Service
{
public class SimpleBinder extends Binder
{
SimpleService getService()
{
return SimpleService.this;
}
}
private final IBinder binder = new SimpleBinder();
@Override

public IBinder onBind(Intent intent)
{
return binder;
}
@Override
public void onCreate()
{
System.out.println("onCreate() called");
}
@Override
public void onDestroy()
{
System.out.println("onDestroy() called");
}
}

Listing 1–6 first declares a SimpleBinder inner class that extends the android.os.Binder class. simpleBinder declares a single SimpleService getService() method that returns an instance of the SimpleService subclass.

NOTE: Binder works with the IBinder interface to support a remote procedure call mechanism for communicating between processes. Although this example assumes that the service is running in the same process as the rest of the app, Binder and IBinder are still required.

Listing 1–6 next instantiates SimpleBinder and assigns the instance’s reference to the private binder field. This field’s value is returned from the subsequently overriding onBind(Intent) method. Let’s assume that the SimpleActivity class in Listing 1–2 declares a private SimpleService field named ss (private SimpleService ss;). Continuing, let’s assume that the following code fragment is contained in SimpleActivity’s onCreate(Bundle)  method:

ServiceConnection sc = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
ss = ((SimpleService.SimpleBinder) service).getService();
System.out.println("Service connected");
}
public void onServiceDisconnected(ComponentName className)
{
ss = null; System.out.println("Service disconnected");
}
};
bindService(new Intent(SimpleActivity.this, SimpleService.class), sc, Context.BIND_AUTO_CREATE);

This code fragment first instantiates a ServiceConnection subclass. The overriding onServiceConnected(ComponentName, IBinder) method concerns itself with using the service argument to call SimpleBinder’s getService() method and save the result.

Although it must be present, the overriding onServiceDisconnected(ComponentName) method should never be called, because SimpleService runs in the same process as  SimpleActivity.
The code fragment next passes the ServiceConnection subclass object, along with an intent identifying SimpleService as the intent’s target and Context.BIND_AUTO_CREATE (create a persistent connection), to bindService(Intent, ServiceConnection, int).

NOTE: A service can be started (with startService(Intent)) and have connections bound to it (with bindService(Intent, ServiceConnection, int). In this situation, Android keeps the service running as long as it’s started, or one or more connections with the BIND_AUTO_CREATE flag have been made to the service. Once neither of these situations holds, the service's onDestroy() method is called and the service is terminated. All cleanup work, such as stopping threads or unregistering broadcast receivers, should be finished upon returning from onDestroy().
Regardless of how you start the service, the app’s AndroidManifest.xml file must have an entry for this component. The following entry declares SimpleService:




NOTE: Although the previous example used bindService(Intent, ServiceConnection, int) to start a local service, it’s more typical to use this method to start a remote service.