Android Services: A Tutorial
What is a service
A service is simply code which is running , and this code , does not have a GUI . The code runs , on the main thread of its application (hosted process) , unless the code creates , a runnable thread , or is run in a separate process .
The code can either show a notification indicating that it is running , in such a case , it is foreground code . A notification , must be shown when accessing , for example the microphone , or the camera .
The code can show no indication , that it is running , in such a case , it is background code , like for example , emptying the cache folder of an application .
The code can be interacted with , like for example to send a specific request , or to receive a given result . In such a case , the code is available , as long , as the code that it is interacting with , is available . This is bound code .
A code can be bound , and show a notification , or show no notification , or a code can be unbound , and show a notification , or show no notification .
A service , so the code that can be bound , or unbound , or showing , or not showing a notification , is created using the Service
class , and is started using an Intent
.
Service lifetime and lifecycle
The code of an instance of a class , has a life time , which is the period during which the instance exists . So a service also , has a lifetime .
A lifetime has a cycle , which is when the instance is first created , lastly destroyed , and what happens in between.
From android developers , the service lifecycle is as follows
So for example , when startService
is called , the code specified in onStartCommand
will get executed , and it can be used to show a notification , so the service will be a foreground service , or no notification , so the service will be a background service .
After that , a call to bindService
, can be made . The code specified in onBindService
, will get executed . It must return an interface , which allows communication with a code . The code is bound to the lifetime of the clients , hence this is known as a bound service .
Lifetime flags
An instance of a Service
, can have some flags set to it . These flags control the lifetime of the instance , of the Service
.
These flags are only applicable , to a service which is started by calling startService
. A service which has only the bindService()
method called , is destroyed , when all the bound clients , have unbound .
The START_STICKY
flag states , that when an instance of a Service
is destroyed , for example on low memory , another instance of this service , will be created , as such the onCreate
, and on onStartCommand
will be called . The executing code is restarted from scratch , and no state is preserved . The original Intent
, which started the first instance of the Service
, is not re-passed to the onStartCommand
, hence it is null .
The START_REDELIVER_INTENT
flag dictates , that when an instance of a Service
is destroyed , what happens , is that another instance of the Service
is created . The executing code , is restarted from scratch , the onCreate
, and onStartCommand
functions are executed , in this case , the onStartCommand
will receive the original Intent
, that started the earlier instance , of the service .
The START_NOT_STICKY
flag states , that when an instance of a Service
is destroyed , it is not recreated , so it must be manually recreated .
A service which is showing a notification , has the same priority as an application which is running in the foreground , so it is less likely that it will be killed on low memory , but the important thing to remember , is that this is not important .
Registering a service
A Service must be declared in the manifest of an application , by adding a service
element , as a child , to the application
element .
If the service is a foreground service , then uses-permission
foreground service , must be specified in the manifest .
Also if the service is a foreground service , then using foregroundServiceType
, it must state its type , which can be one or more , for example camera
, or camera | microphone
The only required attribute , is the name
attribute , which specifies the name of the class , that implements the service . The name of the class can either be fully qualified , by specifying the package to which this class belongs , or it can start with a dot .
, in this case , it belongs to the package specified in the manifest .
A service can run on a different process , then the default process , created for the application , by using the process
attribute . If the string name , in the process attribute , starts with a colon :
, then the service will run in a newly created process , private to its application . If the string name , starts with a lower case letter , than the service will run in a global process , having the indicated name .
Starting , and stopping a service
A service can be started by calling startService
, a service started by calling startService
, is called a started service .
Intent intent = new Intent (this , Service_ClassName.class );
startService (intent );
Data can be added to an intent , like to specify some options , to the Service .
Intent intent = new Intent (this , Service_ClassName.class );
intent .putExtra ("do" , "what" );
intent .putExtra ("what-arg" , 0.5 );
startService (intent );
The startService
method , can be called multiple times , as such the onStartCommand
, can also be called multiple times .
A service started using the startService
method , can be stopped using the stopService
method .
Intent intent = new Intent (this , Service_ClassName.class );
stopService (intent );
It can also stop itself , using : stopSelf (int startId )
. The startId
in stopSelf
, is the one received from the onStartCommand
. It is used to prevent the service from stopping itself , if new startService
calls , have been issued , but if the most recent startId
is used , then the service will stop itself , disregarding any previous startService
calls .
A started service can display a notification that it is running , and promote itself to a foreground service , by using the startForeground
method , which takes as parameters , a user defined notification id , and the actual notification , to display to the user .
startForeground (int id, Notification notification)
To demote a foreground service , back to being a background service , the stopForeground
method can be called . This does not stop the service from running . The stopForeground
method , can also be passed a boolean
true , to remove any displayed notifications . Now that the service is demoted , to being back a background service , it can be stopped as explained earlier , using stopSelf
, or stopService
.
A service can be started by calling the bindService
method , which has the following signature :
public abstract boolean bindService (Intent intent,
ServiceConnection events,
int options)
The intent is just a regular intent to start a service , as shown earlier .
events , is just an instance of an interface , which must respond to the different binding events , that occurs , for example , onBindingDied
, or onServiceConnected
, or onServiceDisconnected
.
options is just the options to control the binding process , for example the flag BIND_AUTO_CREATE
, will automatically create the service .
If the service class exists , and the client is allowed to bind to it , the bindService
method , returns true , otherwise it returns false .
When the binding is being performed , the onBind
method is called , and it must return an instance of the IBinder
interface . Binding is more related to interprocess communication , so to communicate between different process , but can be used in all cases . The binder class , implements the methods , that allow performing the interprocess communication , and we can extend it , to provide our own methods , as a service to a client .
A bound service , can be unbound , and stopped by using the unbindService
method .
A service which has only its bindService method called , is automatically destroyed , when all the bound clients unbind , so after the onUnbind
method is called .
If a service has been started using the startService
method , and also started using the bindService
method , then calling the stopService
or stopSelf
methods , will not destroy this service , until all bound clients have unbound , and vice versa , when all clients have unbound , but the stopSelf
or stopService
methods , have not been called , the service will not be destroyed .
Getting results from a service
A service started using the startService
method , can use for example a toast , or a notification , or a broadcast … to provide or show some results . It can also be made bound , in order to retrieve results when necessary .
Demo application
This application illustrates all the points , talked about earlier . It has three services , one is used to purge the content of the cache directory , the second is used to record audio , and the third is used to interact with some code , so just to calculate the addition of n
numbers , and to stop a started recording session .
The Service source code is as follows :
The main activity source code is as follows :
And the manifest source code is as follows :
IntentService
An IntentService , is a service which is an instance , of the IntentService
class . The IntentService
class is a subclass of the Service
class .
The IntentService
class , uses a single worker thread , when a call to startService
is made , as not to implement one’s own thread . This thread is different from the application main thread .
Calls made to startService
, are processed sequentially , on this newly created thread , one after another , and the IntentService
automatically stops itself , when no more work is to be done .
IntentService
is deprecated , and JobIntentService
must be used instead .
Originally published at https://twiserandom.com on February 16, 2021.