Thursday 21 November 2013

Android Example: Communication between Activity and Service using Messaging


Android_robot


ANDROIDMOBILEPROGRAMMING

Android Example: Communication between Activity and Service using Messaging






                                                           I recently wrote my first little app for my Android smartphone and I was surprised how easy it was. Being familiar with regular Java, learning the new Android APIs was very simple for the most part. However, there was one thing that wasn’t particularly straight forward: communicating between an Activity, i.e. the user interface, and a backgroundService started by the application. After many hours, I found some sample code on Stack Overflow which I used to create a very generic reusable solution to start, stop and communicate with your own Service implementation.
The code below provides an easy way to:
  • Implement your own Android background Service
  • Start and stop the service from an Activity, i.e. the UI
  • Send/receive messages by the Service
  • Send/receive messages by the Activity

Solution

Here are three simple steps how to use my code:
  • Download and import the two Java classes AbstractService and ServiceManager
  • Inherit from AbstractService to implement your own service.
  • Add a ServiceManager to your Activity.
You can now:
  • Control the service with ServiceManager.start() and .stop()
  • Send messages to the service via ServiceManager.send()
  • Receive messages from the service by passing a Handler in the ServiceManager constructor
  • Send messages from the service to all listeners using AbstractService.send()
  • Receive messages in the service via the onReceiveMessage() callback

Example

Here is a small excerpt that shows how to use the code, i.e. how to implement your service and control it from the activity. You can find a full example on Launchpad.
Step 1: Inherit from AbstractService: Override onStartService, onStopService and onReceiveMessage, and use send() to send messages to the activity.
public class SomeService1 extends AbstractService {
  public static final int MSG_INCREMENT = 1;
  public static final int MSG_COUNTER = 2;
    
  private Timer timer = new Timer();
  private int counter = 0, incrementby = 1;
 
  @Override
  public void onStartService() {
    // Increment counter and send to activity every 250ms
    timer.scheduleAtFixedRate(new TimerTask(){
      public void run() {
        try {
          counter += incrementby;
          send(Message.obtain(null, MSG_COUNTER, counter, 0));
        }
        catch (Throwable t) { }
      }, 0, 250L);
    }
  }
    
  @Override
  public void onStopService() {
    if (timer != null) {timer.cancel();}
    counter = 0;
  }  
 
  @Override
  public void onReceiveMessage(Message msg) {
    if (msg.what == MSG_INCREMENT) {
      incrementby = msg.arg1;
    }
  }
}
Step 2: Use the service in an activity with a ServiceManager: Instantiate a service manager, control the service with .start()/.stop() and send messages to the service with .send(). Note: To unregister the activity from the service, you should call .unbind() in the onDestroy()-callback.

public class ExampleActivity extends Activity {
  private ServiceManager service;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {        
    // Create a service 'SomeService1' (see below) and handle incoming messages
    this.service = new ServiceManager(this, SomeService1.class, new Handler() {
      @Override
      public void handleMessage(Message msg) {
        // Receive message from service
        switch (msg.what) {
          case SomeService1.MSG_COUNTER:
            textValue1.setText("Counter @ Service1: " + msg.arg1);                    
            break;
                    
          default:
            super.handleMessage(msg);
        }
      }
    });
 
    // Now you can control the service via .start(), .stop()
    service.start();
    service.stop();
 
    // Or send messages to it
    service.send(Message.obtain(null, SomeService1.MSG_VALUE, 12345, 0));          
  }
 
  @Override
  protected void onDestroy() {
    super.onDestroy();
    
    try { service.unbind(); }
    catch (Throwable t) { }
  }
 
  ...
}