Android Services: A Tutorial

mohamad wael
Analytics Vidhya
Published in
8 min readFeb 16, 2021

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 unbindServicemethod .

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 stopSelfmethods , will not destroy this service , until all bound clients have unbound , and vice versa , when all clients have unbound , but the stopSelf or stopServicemethods , 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.

--

--