Android - Communication with Services

Tuesday 9 December 2014



As defined by the developer.android site a Service is a application component that can perform long running tasks in the background without an user interface. It can run on a separate process or on the same process as the Activity that started the Service and it will continue to run in the background even if the user switches to another application. Additionally a component can bind to a service to interact with it or even perform inter process communication. We will look into how to make this work but first we must understand the two forms a Service might take:
Bound form - In bound form an application component binds to the Service and allows Components and Service to interact with each other.
Started Free Form - Once started a service can run if free indefinitely or till the task completes depending or restart itself with a null or the same intent depending upon the use.

Creating the Service:

We can create a Service by extending the Service class of Android and overriding the callback methods. Also we need to declare the service in the Manifest file of the application. To have a clear idea of the running have a look at what might be the life cycle of a Service in Android in both bound and started form.

Once running, a service can notify the user of events using Toast Notifications or Status Bar Notifications.For a detailed understanding you can go through the examples in the developer site : http://developer.android.com/guide/components/services.html

Bound Service and Communication:
There are three cases that we will discuss which are enumerated below:
1. When the Service and the Application both belong to the same process then by implementing a binder they can communicate by calling public methods of the Service [TODO]
2. Implementing a Messenger to handle IPC requests
3. Implementing AIDL to allow the operating system to pass the message between boundaries.

In this post we will handle only case one after which we will follow up on the other cases in the upcoming posts. In our example we call a Activity that fires up a service if it is not running which then which then fires up the activity based on a boolean value present in the activity.The code along with the explanation in comments is given below.

//MainActivity.java
package com.example.activityservicecommunication;

import com.example.activityservicecommunication.MyService.MyBinder;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 private final String serviceName = "com.example.activityservicecommunication.MyService";
 private boolean isRanging = false;
 
 MyService myservice; //stores the current instance of the Service
 boolean isBound = false; //value to check if the current instance is present
 
 /**
  * This connection is given which assigns our service class with the instance of the 
  * running service when the activity binds to the service and sets the value of the bound
  * variable as true.
  */
 private ServiceConnection myConnection = new ServiceConnection(){

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   MyBinder binder = (MyBinder) service;
   myservice = binder.getService();
   isBound = true;
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   isBound = false;
  }
  
 };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(isMonitoringServiceRunning()){
         //donot fire up
         Toast.makeText(getApplicationContext(), "Service already running", Toast.LENGTH_SHORT).show();
        }else{
         //fire up the service
         Toast.makeText(getApplicationContext(), "Starting Service", Toast.LENGTH_SHORT).show();
         Intent serviceIntent = new Intent(getApplicationContext(),MyService.class);
         bindService(serviceIntent,myConnection,Context.BIND_AUTO_CREATE);
        }
        //simulate the changing values of the variables
        new Handler().postDelayed(new Runnable(){

   @Override
   public void run() {
    isRanging = true;
    if(isBound){
     Toast.makeText(getApplicationContext(), "You should get Notifcation now", Toast.LENGTH_SHORT).show();
     myservice.setRanging();
    }
    new Handler().postDelayed(new Runnable(){

     @Override
     public void run() {
      isRanging = false;
      if(isBound){
       Toast.makeText(getApplicationContext(), "You should get Notifcation now", Toast.LENGTH_SHORT).show();
       myservice.unsetRanging();
      }
     }
     
    }, 5000);
   }
         
        }, 5000);
    }
    

 @Override
 protected void onStop() {
  super.onStop();
  if(isBound){
   unbindService(myConnection);
   isBound = false;
  }
 }




 private boolean isMonitoringServiceRunning(){
     ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
     for(RunningServiceInfo service:manager.getRunningServices(Integer.MAX_VALUE)){
      Log.d("MESSAGE",service.service.getClassName());
      if(serviceName.equals(service.service.getClassName())){
       return true;
      }
     }
     return false;
    }
}



package com.example.activityservicecommunication;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;

public class MyService extends Service {
 
 private final IBinder mbinder = new MyBinder();
 private boolean isRanging = false;
 private boolean prevValue = false;
 private NotificationManager notificationManager;
 private static final int NOTIFICATION_ID = 123;
 
 public class MyBinder extends Binder{
  MyService getService(){
   return MyService.this;
  }
 }

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

 @Override
 public void onCreate() {
  notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  new Thread(){

   @Override
   public void run() {
    while(true){
     if(isRanging!=prevValue){
      postNotification("Rabging Value Changed");
      prevValue = isRanging;
     }
    }
   }

   
  }.start();
  super.onCreate();
 }
 
 public void setRanging(){
  isRanging = true;
 }
 
 public void unsetRanging(){
  isRanging = false;
 }
 
 private void postNotification(String msg) {
     Intent notifyIntent = new Intent(MyService.this, MyService.class);
     notifyIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
     PendingIntent pendingIntent = PendingIntent.getActivities(
       MyService.this,
         0,
         new Intent[]{notifyIntent},
         PendingIntent.FLAG_UPDATE_CURRENT);
     Notification notification = new Notification.Builder(MyService.this)
         .setSmallIcon(R.drawable.beacon_gray)
         .setContentTitle("Notify Demo")
         .setContentText(msg)
         .setAutoCancel(true)
         .setContentIntent(pendingIntent)
         .build();
     notification.defaults |= Notification.DEFAULT_SOUND;
     notification.defaults |= Notification.DEFAULT_LIGHTS;
     notificationManager.notify(NOTIFICATION_ID, notification);
   }

}  

Put in some xml layout according to the code and register the service in the manifest. You should see two notifications coming up according to when the activity changes the isRanging value in the Service via the public methods.
Copyright @ 2013 code-craft. Designed by Templateism | MyBloggerLab