Services run in the main thread
Services run in the main thread of the app’s process. You can specify that it run in its own thread and process if you want. For more on processes, have a look at the article, Processes and Threads.
Start a separate thread in your Service to do the work
You should create a separate thread within the service to do any heavy work. Need a tutorial on threads? Have a look at the Using Threads Tutorial.
When should you use a Service or a Thread?
Use a Service if you need work done in the background without the user interacting with it.
Use a Thread if you want work done off the main thread while the user is interacting with your app.
What would you use a Service for?
Services are designed to be long-lived. They will survive even if the components that started them are killed. They’re ideal for running time-consuming operations, like these:
- Network transactions
- Database transactions
- Playing music
- Updating Content Providers
Blue murder: your Service can get killed
Services will be killed by the system if their resources are needed elsewhere.
You can set your Service’s priority to that of a foreground activity, making it unlikely to be killed. The downside is that it will be using resources that may be needed elsewhere.
You can configure your Service so that if it is killed it will restart when resources are available.
Take two: The two forms of a Service
You can use either or a combination of both.
- Started Service – an app component calls startService() to start the service. This form of Service is usually used to perform a single task. The Service should stop itself when the task is finished
- Bound Service – this form of Service acts as a server for the component. An app component binds itself to the Service by calling bindService(). The component can then interact with the Service. The Service only lives for as long as the component is bound to it
In the beginning: Creating a Service
To create a Service, you need to create a subclass of the Service class (or an existing subclass) and then override a number of callbacks.
After creating the Service, you must register it in the AndroidManifest.xml file. You can include permissions to prevent other apps from accessing your service.
There are two Service classes that you can extend to create a service:
- Service Class – this is the base class. If you extend this class to create your Service then you should create a separate worker thread within your Service to do the work
- IntentService – this is a subclass of the Service class. It’s the quickest and easiest way to use a Service. Maybe you’ll be interested in this tutorial, Using an IntentService to do background work.
Here are the most important Service callbacks:
Callbacks you should implement in your Service
More on the onStartCommand()
This method is called by the system to start the service when startService is called. It’s also called when a Service is restarted after being killed by the system.
onStartCommand runs on the main thread. This is where you can create your worker thread.
It returns a value that determines how the system should respond if the Service is restarted after the system killed it.
You can control the restart behaviour by returning:
- START_STICKY – this is the standard behaviour. It ensures that onStartCommand is called for Service restarts after being killed. The intent parameter will be null. Typically used for Services that are started with startService()
- START_NOT_STICKY – used for Services started for a specific action and then stop themselves when complete. Will only restart if there are pending start calls. Ideal for services handling specific requests, e.g. Updates. No restart is performed if resources are low but will rather wait for the next scheduled start
- START_REDELIVER_INTENT – used when you want to make sure that the Service completes its task. Will only restart if there are pending start calls or if it was killed before stopping itself
The mode you choose, determines the parameters that will be passed to onStartCommand on restarts. When first called, it receives the intent you passed in your startService() call.
If you returned START_STICKY then on restart, when onStartCommand is next called, the intent will be null.
If you returned START_REDELIVER_INTENT then on restart, when onStartCommand is next called, it will receive the original intent.
The flag parameter
You can use the flag parameter to discover how the service was started, like this:
Use flags to determine how the Service was restarted
Go: Starting a Service
To start a Service, an app component calls startService(), passing an intent as a parameter. The intent specifies the Service and any extra data it can use.
What’s your intent? Implicit or Explicit Intents
You can start the Service using an:
- implicit Intent – where you specify an action that you want performed. The system will then look for components that can perform that action
- explicit Intent – you specify a particular Service that you want to start
Halt: Stopping a Service
A Service can run indefinitely. It will only stop if the system kills it or you stop it. You should stop it when it’s no longer needed.
There are two ways that you can stop a Service:
- stopSelf() - you can ask the Service to stop itself when it’s finished working. Passing no parameter kills the Service immediately. Passing the startId will make sure that if any started Services still have work to be done, then that work will be done before the Service is stopped
- stopService() – called by another component to stop the Service. Pass the Intent that started it as a parameter
You don’t have to stop a bound Service, the system destroys it when all the bound components have unbound from it.
Working in the Chain gang: Bound Services
Using a bound Service is a bit more complicated than a started Service. We’ll just cover a brief outline here.
Why use a bound Service?
Use a bound Service if you need your app components to interact with the Service.
Any of your application’s components can bind to a Service
Multiple clients can bind to the Service at once.
You can also bind to Services running in another process. You can then communicate with them via broadcast intents or through extras in the intents used to start the service.
A bound Service stops once all components unbind from it.
Create a bound Service
Implement onBind() which returns an IBinder. IBinder defines the interface that components use to interact with the Service.
Starting a bound Service
Call bindService() to start a bound Service.
Components call bindService() to bind to the Service, retrieve the IBinder interface and begin communicating with the Service.
Stopping a bound Service
When a component has finished using the Service, they call unbindService() to unbind from it. When all components have unbound from the Service, it is destroyed.
For more on bound Services, have a look at Bound Services: What you should know!
In plain sight: Creating a foreground Service
The Android system ranks running Services second in priority behind active activities. They are therefore second last on the list of components to be killed for their resources.
You can set your Service’s priority to that of a foreground activity. Simply call its startForeground() method. This will make it virtually impossible for runtime to kill your foreground Service.
Only use foreground Services if absolutely necessary as they tie up resources. If you do use a foreground Service then you must send an ongoing notification informing the user that the Service is running. They should then be able to stop it at any time.
You can move a foreground Service to the background by calling stopForeground().
If you're interested, here's the first in a series of tutorials on using Services.
I hope that you have found this tutorial helpful.