The document discusses implementing inter-process communication (IPC) using Messenger in Android. It describes how a Messenger allows a service to expose a Handler to clients so they can send messages to be processed on the service's thread. The service returns a Messenger from onBind() and clients use it to send messages to the service's handler. The document provides code samples for implementing this in a service and client. It also compares Messenger to AIDL which allows concurrent IPC across processes but requires more setup.
2. Introduction to IPC using Messenger
• Android offers a mechanism for inter-process communication (IPC) using remote
procedure calls (RPCs), in which a method is called by an activity or other
application component, but executed remotely (in another process), with any
result returned back to the caller.
• This entails decomposing a method call and its data to a level the operating system
can understand, transmitting it from the local process and address space to the
remote process and address space, then reassembling and re-enacting the call
there.
• Return values are then transmitted in the opposite direction.
• Android provides all the code to perform these IPC transactions, so you can focus
on defining and implementing the RPC programming interface.
3. Android Interface Definition Language versus
Messenger
• Using AIDL is necessary only if you allow clients from different applications to
access your service for IPC and want to handle multithreading in your service.
• If you do not need to perform concurrent IPC across different applications, you
should create your interface by implementing a Binder or, if you want to perform
IPC, but do not need to handle multithreading, implement your interface using a
Messenger.
• Executing all the tasks (passing messages) is sequential by design as the
messages are processed on a single thread by the Handler to which it belongs
whereas AIDL can execute tasks concurrently on binder threads.
4. Implementation in Service
• The Service should implement (contain) a Handler instance that receives a call-back
(using handleMessage() for instance) for each call from the client.
public class LocationService extends Service {
public static final int REQUEST_LOCATION= 1;
class ServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case REQUEST_LOCATION :
replyLocation(40.22,32.21);
break;
default:
super.handleMessage(msg);
5. Implementation in Service
The Handler is used to create a Messenger object which in itself is actually a reference
to the Handler.
The Messenger creates an IBinder (via getBinder()) that the Service returns to
clients from onBind().
//Inside LocationService
Messenger mServiceMessenger = new Messenger(new ServiceHandler());
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
6. Implementation in Client
Clients use the IBinder object in its ServiceConnection implementation to instantiate
the Messenger object.
Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
}
}
7. Implementation in Client
This messenger refers to Service’s Handler which the client uses to send Message (with
send() for instance) objects to the Service’s Handler. So the Service receives the
messages in its Handler.handleMessage().
private void requestLocation() {
Message msg = Message.obtain(null, LocationService.REQUEST_LOCATION);
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
8. Changes in Manifest
Make sure to have this entry in your manifest in order for the Service to work properly in a
different process.
<service
android:name="com.example.app.LocationService"
android:process=":my_process">
</service>
If the name assigned to this attribute begins with a colon (':'), a new process, private to the
application, is created when it's needed and the service runs in that process.
If the process name begins with a lowercase character, the service will run in a global
process of that name, provided that it has permission to do so. This allows components in
different applications to share a process, reducing resource usage.
9. Modifications in Incoming Handler
Weak References
A weak reference, simply put, is a reference that isn't strong enough to force an object
to remain in memory. Weak references allow you to leverage the garbage collector's
ability to determine reachability for you, so you don't have to do it yourself. You create
a weak reference like this:
WeakReference weakWidget = new WeakReference(widget);
and then elsewhere in the code you can use weakWidget.get() to get the
actual Widget object. Of course the weak reference isn't strong enough to prevent
garbage collection, so you may find (if there are no strong references to the widget)
that weakWidget.get() suddenly starts returning null.
10. Modifications in Incoming Handler
If IncomingHandler class is not static, it will have a reference to
your Service object.
static class ServiceHandler extends Handler {
private final WeakReference<LocationService> mService;
ServiceHandler(LocationService service) {
mService = new WeakReference<LocationService>(service);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case REQUEST_LOCATION :
mService.replyLocation(40.22,32.21);
break;
default:
super.handleMessage(msg);
11. Android Interface Definition Language
Concept
AIDL allows you to define the programming interface that both the client and
service agree upon in order to communicate with each other using inter-process
communication.
If you do not need to perform concurrent IPC across different applications, you
should create your interface by implementing a Binder or, if you want to perform
IPC, but do not need to handle multithreading, implement your interface using a
Messenger.
Using AIDL is necessary only if you allow clients from different applications to access your
service for IPC and want to handle multithreading in your service.
12. Android Interface Definition Language
Defining an AIDL interface
To create a bounded service using AIDL, follow these steps:
Create the .aidl file
This file defines the programming interface with method signatures.
Implement the interface
The Android SDK tools generate an interface in the Java programming language, based
on your .aidl file. This interface has an inner abstract class named Stub that
extends Binder and implements methods from your AIDL interface. You must extend
the Stub class and implement the methods.
Expose the interface to clients
Implement a Service and override onBind() to return your implementation of
the Stub class.
13. Create the .aidl file
// IRemoteService.aidl
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
int getPid();
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
Here is an example .aidl file:
Simply save your .aidl file in your project's src/ directory and when you build your application, the SDK tools
generate the IBinder interface file in your project's gen/ directory.
14. Implement the interface
public class RemoteService extends Service {
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};
15. Expose the interface to clients
IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder
service) {
mIRemoteService = IRemoteService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
mIRemoteService = null;
}
};