What is a Service?

  • A service is a component that runs in the background to perform long-running operations.
  • A service does not provide a use interface.
  • Another application component (Activity/BroadcastReceiver/Content Provider) can start a service , and the service continues to run even the component that started is destroyed or user swithches to other application.

Example: A service might play music in background while the user is interacting with other app.
Service might fetch data over the network without blocking user interaction with activity.

How to implement a service?

A service is implemented as subclass of Service.

How many types of services can be implemented?

There are 3 different types of services:
(1) Foreground
(2) Background
(3) Bound

Foreground:
The foreground service performs some operation that is noticeble to user.
Ex:Audio track played by music player is noticeble to user as it is displayed as notification.
Foreground services continue to run even the user is not interacting with app.

Background:
A Background service performs operation that is not noticeble to user.
Ex:Fetching a Data from server periodically and updating the local DB.

Bound:
A service is said to be bound when an application component binds to it by calling bindService().
Bound service provides Client-Server interface that allows components to interact with service, send requests ,receive results.
Multiple components can bind to the service at once, when all of them unbind,service is destroyed.

Where will Service run ?

A service runs in your application’s main thread by default.
If the service performs any operation that blocks user interface, consider creating a new thread in the service so that service will not block the user interaction.

What are the important callback methods that needs to be overridden in the service implementation?

(1) onCreate()
(2) onStartCommand()
(3) onBind()
(4) onDestroy()

onCreate()
The system invokes this method when the service is initially created ,to perform one time setup procedures.
Called before onStartCommand() and onBind()

onStartCommand()
Called when an application component starts a service by calling startService().
When this method is called the service starts and runs indefinitely in the background . Its is your responsibility to stop the service by calling stopService() or stopSelf()

onBind()
Called when an application component binds to the service by calling bindService().
The bound service provide client server interface, that allows component to interact with the service by sending requests,receive responses.
Returns IBinder interface which the clients use to interact with the service.

onDestroy()
Called when the service is no longer used and is destroyed.

What are the classes that we use to create a service?

There are 2 classes you can extend to create a service :

(1) Service class :

This is base class of all services. When you create a service extending Service class , since By default the service runs on Main Thread,we need to create a new Thread to perform operations that blocks or slows down the performance of an activity . This service runs indefinitely till the operation is completed ,its responsibility of the user to stop the service when its work is done by calling stopSelf() or stopService()

(2) IntentService:
(1) Creates a worker Thread that executes all the intents that are delivered to onStartCommand() ,separate from the application’s MainThread.
(2) Create a worker Queue that delivers only one intent at a time to onHandleIntent() so that we never have to worry about multithreading.
(3) Once all the Intents are handled so that the Service stops itself without explicitly calling stopSelf()
(4) Provides default implementation of onBind() and onStartCommand() that delivers the intent to worker queue which delivers one intent at a time to onHandleIntent()

Example code for IntentService:

public class MyService extends IntentService { //Constructor specifies the worker Thread name
public MyService(){
super("MyService")
}
protected void onCreate(Bundle onSavedInstance){
//Do one time set up procedures
}
public int onStartCommand(Intent intent,int flags,int startId){
return super.onStartCommand(intent,flags,startId)
}protected void onHandleIntent(Intent intent) {
//Do service long running operation here.
}
protected IBinder onBind(Intent intent){return null;
}

}

Sample code for Extending service class:

public class MyService extends Service{
protected void onCreate(Bunble b){
//Do one time set up procedures
}
protected int onStartCommand(Intent intent ,int flags, int startID) {
//Do service long running operation here.
//Spawn a new thread to perform operation that blocks user interface
}protected void onDestroy(){}protected IBinder onBind(Intent intent){return null;
}
}

What are the different types of Bound services?

There are 2 Types of Bound services:
(1) Local Binding
(2) Remote Binding

(1) Local Binding :
The components which are interested in binding to a service are of same application process ,then its called Local Binding . Which means both the component interested in binding to service and the service are part of same app.
(2) Remote Binding :
If the service and the component that want to bind to that service are of different app process/ or different applications then it Remote Binding.

Behavior of Bound Services:
(1) Component can bind to started,un-started and stopped service
(2) Any number of components can bind to the service.
(3) Bound service is stopped when all the components bound to it are unbound.

Implementation of Local binding and Remote Binding:
Local Binding is implemented using IBinder interface where as Remote binding is implemented using Messenger and AIDL.

Local Binding using IBinder interface:

(1) Service implements IBinder interface and returns IBinder from onBind() method.

(2) Activity uses ServiceConnection API to bind to service.

Local Bound Service implementation:

Step1 : Create a class that extend Binder or implements IBinder interface. ( Note:Binder is an Abstract class that implements IBinder Interface )

Create a method in LocalBinder class that returns Service .

For Example service name is LocalBinderService.

class LocalBinder extends Binder {
public LocalBindService getService(){ return LocalBindService.this;}
}

Step2 : Create instance of LocalBinder class

LocalBinder localBinder = new LocalBinder();

Step3: Return localbinder instance from onBind() method

@Override    public IBinder onBind(Intent intent) {  
return localBinder;
}

Step4: Create a method that returns result from service say service returns a message to the bound component.

private String serviceInfo = "";
public String fetchServiceInfo(){ return serviceInfo; }

Step5: The onStartCommand() performs long running operation. Here it sets message that needs to be returned from service.

protected int onStartCommand(Intent intent,int flags,int startID) {
canFetchInfoFromService = true;
int i = 0;
new Thread(){
public void run(){
while(canFetchInfo){
i++;
serviceInfo = "Hi"+i;
}
}
}.start();
return START_STICKY; }

Activity Side implementation:

Step1 : Create a ServiceConnection object and override the onServiceConnected() and onServiceDisConnected() methods.

Once you receive serviceconnection send that as part of bindService() method to bind to that service

public bindService(){
if(serviceConnection == null) {
serviceConnection = new ServiceConnection(){

public void onServiceConnected(ComponentName cnName,IBinder iBinder){
LocalBindService.LocalBinder localBinder = (LocalBinderService.LocalBinder)iBinder;
myService = localBinder.getService();}
public void onServiceDisConnected(ComponentName cName){ }
}
bindService(serviceIntent,serviceConnection,context.BIND_AUTO_CREATE)
}
}

Step2: Fetch the result from service as below:

public String fetchInfoFromBindService(){
myService .fetchServiceInfo()
}

Step3: Unbind the service

public void unBindService() { unbindService(serviceConnection);}

Remote Service Binding Implementation:

We need to use messenger in component from one app to interact with service of other app.

Service Side Implementation:

Step 1:

Declare service in Manifest and set attribute android:exported = true so that the service can be exposed to other apps

Step 2:Create an Handler in the service

This handler sends the message to the component that binds to the service.

myConstant is the constant that we receive as part of request from component to service.

private final int myConstant = 200
private class MYHandler extends Handler{
@override
public void handleMessage(Message msg){
switch(msg.what){
case myConstant :
Message sendMessage = Message.obtain(null,myConstant);
sendMessage.arg1 = getServiceMessage(); //Example: "Hi"

msg.replyTo.send(sendMessage)


break;
}
super.handle(msg);
}
}

Step2: Create a messager object as below:

Messenger messenger = new Messager(MYHandler());

Step3: Return IBinder through messager in onBind()

public IBinder onBind(Intent intent){
messenger.getBinder();
}

Activity side Implementation:

Step 1 : Create 2 Messenger objects. One to send request to service , other to receive response from the service.

Messenger  serviceRequestMessenger,serviceReceiveMesssenger;

Step 2: Create a Handler to receive data from Service

class ReceiveHandler extends Handler{
public void onHandleMessage(Message msg){
switch(msg.what){
case MyConstant:
receivedInfo = msg.arg1;
}
}
}

Step 3: Create a service connection

ServiceConnection sc = new ServiceConnection(){ 
public void onServiceConnected(ComponentName componet,IBinder iBinder){ serviceRequestMessenger = new Messenger(iBinder);
serviceReceiveMessenger = new Messenger(new ReceiveHandler());
}
public void onServiceDisconnected(ComponentName componet){}
}

Step 4: Create explicit Intent for service

Intent intent  = new Intent();
intent.setComponent("packageNameOfService", "packageNameOfService.RemoteService);

Step 5: Bind to Remote service

bindService(intent,sc,BIND_AUTO_CREATE);

Step 6: Make a request to service

private  void makeRequest(){
Message requestMessge = Message.obtain(null,MyCONSTNT);
requestMssge.replyTo = serviceReceiveMesssenger
serviceRequestMessenger.send(requestMessage);
}