Android: communication between Activity and Service

I started to write this stopwatch application for my Android phone, which will help me in my workouts. I decided that it will consist of two major components: an Activity and a Service. The Activity component will provide user interaction and visual data presentation, the Service will take care of time counting and notifying the user about events with sound notifications, so the user won’t have to look at the stopwatch.

In the beginning of the development of this simple application I have learned some things about communication between an Activity and a Service in Android OS.

Sending Intents to the Service

A Service can be started from an Activity with the startService() method:

Intent intent = new Intent(this, TestService.class);
startService(intent);

Above instruction will result in starting the Service and passing the Intent object to it’s onStartCommand() method:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {	
    return super.onStartCommand(intent, flags, startId);
}

When the Service is already running and the Activity invokes startService() with a new Intent object, then Android will pass this new Intent to the onStartCommand(). In an Intent object we can pass data or control command to the Service. Passing new Intent objects to the Service is asynchronous, it’s like send and forget. This is a one-way communication, only from Activity to Service.

Binding to the Service

Another method of communication is Binding to a Service. The Service has to provide the binding interface.

Service (only binding relevant parts):

class TestService extends Service {
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        TestService getService() {
            return TestService.this;
        }
    }
	
    @Override
    public IBinder onBind(Intent intent) {
         return mBinder;
    }

    public int testInterfaceMethod() {
        return Random.getNextInteger();
    }
}

Activity (only binding relevant parts):

class TestActivity extends Activity {
    private CrossfitStopwatchService mService;
    private boolean mBound = false;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
    	}

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mBound = false;
    	}
    };

    @Override
    protected void onStart() {
        Intent intent = new Intent(this, TestService.class);
        startService(intent);
    	
        if (!mBound) {
            bindService(intent, mConnection, BIND_AUTO_CREATE);
        }
    }
}

After the onStart() method of the Activity is finished with it’s job, we should be bound to the Service. The interface is available through the mService member, which was connected with the Binder object. In the Service there is defined on public method, testInterfaceMethod(). This method can be accessed like this:

// probably in an onCLickListener()
int testVal = 0;

if (mBound && mService != null)
    testVal = mService.testInterfaceMethod();

This method of communication is synchronous, unless an internal mechanism will release the thread, which is invoking a Service’s interface method. This method can provide a two-way communication. The Activity asks the Service for something (using one of the Service’s interface methods) and if the method returns a result or the argument is and in/out type, then the Activity can receive an answer.

Using Messengers

A Messenger provides the functionality of an asynchronous message queue. The Messenger can be defined in the Service and in the Activity. Then the Activity asks for the reference to the Service’s Messenger and passes it’s own reference, so the Service can send messages to the Activity.

Below is the code snippet only for the Service Messenger, the same construction can be put in an Activity:

class TestService extends Service {
    public static final int MSG_TEST = 1;
    private final Messenger mIncomingMessenger = new Messenger(new IncomingHandler());

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_TEST:
	         // process message
                 break;
            default:
                super.handleMessage(msg);
                break;
            }
        }
    }
}

For example when an Activity is bound to the Service and the Service provides a method, which will return a reference to it’s Messenger, then the Activity can send messages to the Service:

Messenger serviceMessenger = mService.getMessenger();

Message msg = Message.obtain(null, TestService.MSG_TEST);
serviceMessenger.send(msg);

In the Message object an Activity can put two Integer arguments, an user defined object reference and a reference to it’s own Messenger, which the Service can use to reply.

———

Of course this methods can be mixed together. I decided so and I will try to start a Service, pass an Intent to it, bind and register a listening Activity Messenger, which will wait for timer events form the Service.

Advertisements

2 thoughts on “Android: communication between Activity and Service

    1. Thanks for reading.

      ‘CrossfitStopwatchService’ should be ‘TestService’.

      I used this method of communication on a real app (unfortunately not finished yet) and when I simplified the code for the example I just forgot to change it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s