IPC Bidirectional Communication using Messsengers | Techbirds
In your application generally you wants to communicate your UI thread (e.g. Activity) with your background running thread (e.g. Services) and vice versa… i.e. you want to communicate from your running services to Foreground visible Activity and also wants to send some information from your Foreground Activity to Background running services…
A simple solution of this requirement is to use BroadCast Receivers… But this is heavy component to use in terms of memory and other resources like bandwidth.
Another solution is to use Bound Services.. but that’s a unidirectional communication…
So, the suggested approach is to to use the Messengers…
Other benefits of using Messengers :
> you can also communicate with Remote Processes..
> This technique allows you to perform interprocess communication (IPC) without the need to use AIDL.
Implementation of Messengers :
1. The service implements a Handler that receives a callback and Messages from each client.
2. The Handler is used to create a Messenger object.
3. The Messsenger creates an IBinder that service returns to client from OnBind().
4. Client used the IBinder to instantiate the Messenger, which is used to send Messages to service.
5. Service receives receives each Messages in its Handler ->handleMessage() method.
Here is a simple example of Service that uses Messenger :
public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; Messenger mResponse; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), “hello!”, Toast.LENGTH_SHORT).show(); break; case MSG_REGISTER: mResponse = msg.replyTo; break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), “binding”, Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; Messenger mResponse; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), “hello!”, Toast.LENGTH_SHORT).show(); break; case MSG_REGISTER: mResponse = msg.replyTo; break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), “binding”, Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } } |
If you want the service to be Remote one so that other Apps can use it also use this attribute of Service inside Manifest :
android:process=”:remote” Notice that the handleMessage() method in the Handler i
s where the service receives the incoming Message
and decides what to do, based on the what
member. public sendMessagesToActivity(){ Bundle bundle = new Bundle(); bundle.putString(“message”, “msg”); Message msg = Message.obtain(null, MESSAGE_TYPE_TEXT); msg.setData(bundle); try { mResponse.send(msg); } catch (RemoteException e) { } } Activity Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
android:process=”:remote” Notice that the handleMessage() method in the public sendMessagesToActivity(){ Bundle bundle = new Bundle(); bundle.putString(“message”, “msg”); Message msg = Message.obtain(null, MESSAGE_TYPE_TEXT); msg.setData(bundle); try { mResponse.send(msg); } catch (RemoteException e) { } } Activity Code : |
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound;
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; |
/** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), “hello!”, Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler());
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), “hello!”, Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); |
/** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; // Register our messenger also on Service side: Message msg = Message.obtain(null, MessengerService.MESSAGE_TYPE_REGISTER); msg.replyTo = mMessenger; try { mService.send(msg); } catch (RemoteException e) { } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected — that is, its process crashed. mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported ‘what’ value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
/** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; // Register our messenger also on Service side: Message msg = Message.obtain(null, MessengerService.MESSAGE_TYPE_REGISTER); msg.replyTo = mMessenger; try { mService.send(msg); } catch (RemoteException e) { } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected — that is, its process crashed. mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported ‘what’ value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); |
stopService(new Intent(this, MessengerService.class));
stopService(new Intent(this, MessengerService.class)); |
mBound = false; } } public sendMessagesToService(){ Bundle bundle = new Bundle(); bundle.putString(“message”, “msg”); Message msg = Message.obtain(null, MESSAGE_TYPE_TEXT); msg.setData(bundle); try { mService.send(msg); } catch (RemoteException e) { } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
mBound = false; } } public sendMessagesToService(){ Bundle bundle = new Bundle(); bundle.putString(“message”, “msg”); Message msg = Message.obtain(null, MESSAGE_TYPE_TEXT); msg.setData(bundle); try { mService.send(msg); } catch (RemoteException e) { } } } |
1,444 total views, 1 views today
Share this On