Services
What is a service?
A service is an app component that performs long-running operations, usually in the background. Unlike an Activity
, a service doesn't provide a user interface (UI). Services are defined by the Service
class or one of its subclasses.
A service can be started, bound, or both:
A started service is a service that an app component starts by calling
startService()
.Use started services for tasks that run in the background to perform long-running operations. Also use started services for tasks that perform work for remote processes.
A bound service is a service that an app component binds to itself by calling
bindService()
.Use bound services for tasks that another app component interacts with to perform interprocess communication (IPC). For example, a bound service might handle network transactions, play music, or interact with a database.
A service runs in the main thread of its hosting process—the service doesn't create its own thread and doesn't run in a separate process unless you specify that it should.
If our service is going to do any CPU-intensive work or blocking operations (such as MP3 playback or networking), create a new thread within the service to do that work. By using a separate thread, we reduce the risk of the user seeing "application not responding" (ANR) errors, and the app's main thread can remain dedicated to user interaction with our activities.
To implement any kind of service in your app, do the following steps:
- Declare the service in the manifest.
- Extend a
Service
class such asIntentService
and create implementation code, as described in Started services and Bound services, below. - Manage the service lifecycle.
Declaring services in the manifest
To declare a service, add a <service>
element as a child of the <application>
element. For example:
<manifest ... >
...
<application ... >
<service android:name="ExampleService"
android:exported="false" />
...
</application>
</manifest>
To block access to a service from other apps, declare the service as private. To do this, set the android:exported
attribute to false
. This stops other apps from starting your service, even when they use an explicit intent.
Started services
How a service starts:
- An app component such as an
Activity
callsstartService()
and passes in anIntent
. TheIntent
specifies the service and includes any data for the service to use. - The system calls the service's
onCreate()
method and any other appropriate callbacks on the main thread. It's up to the service to implement these callbacks with the appropriate behavior, such as creating a secondary thread in which to work. - The system calls the service's
onStartCommand()
method, passing in theIntent
supplied by the client in step 1. (The client in this context is the app component that calls the service.)
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 by calling stopSelf()
, or another component can stop it by calling stopService()
.
For instance, suppose an Activity
needs to save data to an online database. The Activity
starts a companion service 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 uses stopSelf()
to stop itself and is destroyed. (This is an example of a service you want to run in a worker thread instead of the main thread.)
IntentService
Most started services don't need to handle multiple requests simultaneously, and if they did, it could be a complex and error-prone multi-threading scenario. For these reasons, the IntentService
class is a useful subclass of Service
on which to base your service:
IntentService
automatically provides a worker thread to handle yourIntent
.IntentService
handles some of the boilerplate code that regular services need (such as starting and stopping the service).IntentService
can create a work queue that passes one intent at a time to youronHandleIntent()
implementation, so you don't have to worry about multi-threading.
IntentService
is subject to the new restrictions on background services in Android 8.0 (API 26). For this reason, Android Support Library 26.0.0 introduces a new JobIntentService
class, which provides the same functionality as IntentService
but uses jobs instead of services when running on Android 8.0 or higher.To implement IntentService
:
- Provide a small constructor for the service.
- Create an implementation of
onHandleIntent()
to do the work that the client provides.
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.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
}
}
Bound services
A service is "bound" when an app 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, and get results, sometimes using interprocess communication (IPC) to send and receive information across processes. A bound service runs only as long as another app component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
Implementing a bound service
To implement a bound service, define the interface that specifies how a client can communicate with the service. This interface, which your service returns from the onBind()
callback method, must be an implementation of IBinder
.
To retrieve the IBinder
interface, a client app component calls bindService()
. Once the client receives the IBinder
, the client interacts with the service through that interface.
There are multiple ways to implement a bound service, and the implementation is more complicated than a started service.
Binding to a service
To bind to a service that is declared in the manifest and implemented by an app component, use bindService()
with an explicit Intent
.
bindService()
with an implicit Intent
.Service lifecycle
A service has no UI, services can continue to run in the background with no way for the user to know, even if the user switches to another app. This situation can potentially consume resources and drain the device battery.
Similar to an Activity
, a service has lifecycle callback methods that we can implement to monitor changes in the service's state and perform work at the appropriate times. The following skeleton service implementation demonstrates each of the lifecycle methods:
public class ExampleService extends Service {
// indicates how to behave if the service is killed.
int mStartMode;
// interface for clients that bind.
IBinder mBinder;
// indicates whether onRebind should be used
boolean mAllowRebind;
@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
}
}
Lifecycle of started services vs. bound services
A bound service exists only to serve the app component that's bound to it, so when no more components are bound to the service, the system destroys it. Bound services don't need to be explicitly stopped the way started services do (using stopService()
or stopSelf()
).
The diagram below shows a comparison between the started and bound service lifecycles.
Scheduled services
For API level 21 and higher, you can launch services using the JobScheduler
API, and with the background service restrictions in API 26 this may be a better alternative to services altogether. To use JobScheduler
, you need to register jobs and specify their requirements for network and timing. The system schedules jobs for execution at appropriate times.
Comments
Post a Comment