For the More Curious: Service Details

We recommend using IntentService for most service tasks. If the IntentService pattern does not suit your architecture for a particular app, you will need to understand more about services to implement your own. Prepare for an infobomb, though – there are a lot of details and ins and outs to using services.

What a service does (and does not do)

A service is an application component that provides lifecycle callbacks, just like an activity. Those callbacks are even performed on the main UI thread for you, just like in an activity.

A service does not run any code on a background thread out of the box. This is the #1 reason we recommend IntentService. Most nontrivial services will require a background thread of some kind, and IntentService automatically manages the boilerplate code you need to accomplish that.

Let’s see what lifecycle callbacks a service has.

A service’s lifecycle

For a service started with startService(Intent), life is fairly simple. There are three lifecycle callbacks.

  • onCreate(…) – called when the service is created.

  • onStartCommand(Intent, int, int) – called once each time a component starts the service with startService(Intent). The two integer parameters are a set of flags and a start ID. The flags are used to signify whether this intent delivery is an attempt to redeliver an intent or is an attempt to retry a delivery that never made it to (or never returned from) onStartCommand(Intent, int, int). The start ID will be different for every call to onStartCommand(Intent, int, int), so it may be used to distinguish this command from others.

  • onDestroy() – called when the service no longer needs to be alive.

The onDestroy() callback is called when the service stops. This can happen in different ways, depending on what type of service you have written. The type of service is determined by the value returned from onStartCommand(…), which may be Service.START_NOT_STICKY, START_REDELIVER_INTENT, or START_STICKY.

Non-sticky services

IntentService is a non-sticky service, so let’s start there. A non-sticky service stops when the service itself says it is done. To make your service non-sticky, return either START_NOT_STICKY or START_REDELIVER_INTENT.

You tell Android that you are done by calling either stopSelf() or stopSelf(int). The first method, stopSelf(), is unconditional. It will always stop your service, no matter how many times onStartCommand(…) has been called.

The second method, stopSelf(int), is conditional. This method takes in the start ID received in onStartCommand(…). This method will only stop your service if this was the most recent start ID received. (This is how IntentService works under the hood.)

So what is the difference between returning START_NOT_STICKY and START_REDELIVER_INTENT? The difference is in how your service behaves if the system needs to shut it down before it is done. A START_NOT_STICKY service will die and disappear into the void. START_REDELIVER_INTENT, on the other hand, will attempt to start up the service again later, when resources are less constrained.

Choosing between START_NOT_STICKY and START_REDELIVER_INTENT is a matter of deciding how important that operation is to your application. If the service is not critical, choose START_NOT_STICKY. In PhotoGallery, your service is being run repeatedly on an alarm. If one invocation falls through the cracks, it is not a big deal, so: START_NOT_STICKY. This is the default behavior for IntentService. To switch to using START_REDELIVER_INTENT, call IntentService.setIntentRedelivery(true).

Sticky services

A sticky service stays started until something outside the service tells it to stop by calling Context.stopService(Intent). To make your service sticky, return START_STICKY.

Once a sticky service is started, it is on until a component calls Context.stopService(Intent). If the service needs to be killed for some reason, it will be restarted again with a null intent passed into onStartCommand(…).

A sticky service may be appropriate for a long-running service, like a music player, which needs to stick around until the user tells it to stop. Even then, it is worth considering an alternative architecture using non-sticky services. Sticky service management is inconvenient, because it is difficult to tell whether the service is already started.

Bound services

In addition to all this, it is possible to bind to a service by using the bindService(Intent, ServiceConnection, int) method. This allows you to call methods on the service directly. ServiceConnection is an object that represents your service binding and receives all binding callbacks.

In a fragment, your binding code would look something like this:

private ServiceConnection mServiceConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
            IBinder service) {
        // Used to communicate with the service
        MyBinder binder = (MyBinder)service;
    }

    public void onServiceDisconnected(ComponentName className) {
    }
};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent i = new Intent(getActivity(), MyService.class);
    getActivity().bindService(i, mServiceConnection, 0);
}

@Override
public void onDestroy() {
    super.onDestroy();
    getActivity().unbindService(mServiceConnection);
}

On the service’s side, binding introduces two additional lifecycle callbacks:

  • onBind(Intent) – called every time the service is bound to and returns the IBinder object received in ServiceConnection.onServiceConnected(ComponentName, IBinder)

  • onUnbind(Intent) – called when a service’s binding is terminated

Local service binding

So what does MyBinder look like? If the service is a local service, then it may be a simple Java object that lives in your local process. Usually this is used to provide a handle to directly call methods on your service:

private class MyBinder extends IBinder {
    public MyService getService() {
        return MyService.this;
    }
}

@Override
public void onBind(Intent intent) {
    return new MyBinder();
}

This pattern looks exciting. It is the only place in Android that enables one Android component to directly talk to another. However, we do not recommend it. Since services are effectively singletons, using them this way provides no major benefits over just using a singleton instead.

Remote service binding

Binding is more useful for remote services, because they give applications in other processes the ability to invoke methods on your service. Creating a remote service binder is an advanced topic and beyond the scope of this book. Check out the AIDL guide in the Android documentation or the Messenger class for more details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.233.223.189