Communication between service and activity – Part 3

After a long time, I found out that Messenger can also be used to communicate between Activity and Services.

What does this Messenger mean?
    It is a Parcelable type, which carries messages from service to activity and vise vera.
    It is similar to aidl, which can work between two different processes.

Quick example how to implement them.
Create a service on launching the activity. On clicking the button in the

Activity:
1. It will have an handler which is responsible for handling all the messages from the service
private class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        String str = (String)msg.obj;
        Toast.makeText(getApplicationContext(),
            "From Service -> " + str, Toast.LENGTH_LONG).show();
    }
}

2. Create a class implementing ServiceConnection Interface
class MyServiceConnection implements ServiceConnection {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mServiceMessenger = new Messenger(service);
        // where mServiceMessenger is used to send messages to Service
        // service is the binder returned from onBind method in the Service
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mServiceMessenger = null;
        unbindService(mCon);
    }
}

3. Create a Messenger Object in OnCreate method with the object of IncomingHandler class
Messenger mActivityMessenger;
mActivityMessenger = new Messenger(new IncomingHandler());

4. Start the service in the onCreate method
Intent lIntent = new Intent(MainActivity.this, MainService.class);
lIntent.putExtra("Messenger", mActivityMessenger);
startService(lIntent);

5. Bind to a service in OnResume method
@Override
protected void onResume() {
    super.onResume();
    Intent lIntent = new Intent(MainActivity.this, MainService.class);
    bindService(lIntent, mCon, 0); // mCon is an object of MyServiceConnection Class
}

6. Unbind the service in OnPause method to avoid Service leakage
@Override
protected void onPause() {
    super.onPause();
    unbindService(mCon);
}

7. Add a onClickListener to the button and send message to service on onClick event.
((Button)findViewById(R.id.button1)).setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d(TAG, "onClick");
        Message msg = new Message();
        msg.obj = "Hi service..";
        try {
            mServiceMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
});

NOTE:
1. Currently string is sent in the message as obj but when the activity and the service are in different process we need to send the string as bundle.
2. If there are more than one activity bound to the service then the service should have a arraylist of client registered and replyTo variable in Message should be set to that activity’s messenger.

Service:
1. It will have an handler which is responsible for handling all the messages from the Activity
private class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        String str = (String)msg.obj;
        Toast.makeText(getApplicationContext(),
    "From Activity -> " + str, Toast.LENGTH_LONG).show();
        Message lMsg = new Message();
        lMsg.obj="Hello Activity";
        try {
            mActivityMessenger.send(lMsg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

3. Create a Messenger Object in OnCreate method with the object of IncomingHandler class
Messenger mServiceMessenger;
mServiceMessenger = new Messenger(new IncomingHandler());

4. Get the extras from the messenger and save it in the local variable
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStartCommand");
    mActivityMessenger = intent.getParcelableExtra("Messenger");
    return super.onStartCommand(intent, flags, startId);
}

5. OnBind return the service messenger’s binder to the activity.
@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind");
    return mServiceMessenger.getBinder();
}