I have an application that communicates with a Service
in a remote process using the Messenger
interface. Here is the basic architecture of how things are set up:
- The application generates several "Operation" objects that require access to the service.
- Each "Operation" contains a
Handler
wrapped in aMessenger
used as a callback receive the response data back from theService
- When the operation executes, it wraps its
Messenger
into anIntent
and callsstartService()
to pass the message to the remote service - The remote service does some work based on the parameters of the
Intent
and then returns the response by sending aMessage
to theMessenger
for that operation.
Here is the basic code present in the operation:
public class SessionOperation {
/* ... */
public void runOperation() {
Intent serviceIntent = new Intent(SERVICE_ACTION);
/* Add some other extras specific to each operation */
serviceIntent.putExtra(Intent.EXTRA_EMAIL, replyMessenger);
context.startService(serviceIntent);
}
private Handler mAckHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//Process the service's response
}
};
protected Messenger replyMessenger = new Messenger(mAckHandler);
}
And a basic snippet of how the service is structured:
public class WorkService extends Service {
private ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//If intent has a message, queue it up
Message msg = mServiceHandler.obtainMessage();
msg.obj = intent;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
private void onHandleIntent(Intent intent) {
Messenger replyTarget = intent.getParcelableExtra(Intent.EXTRA_EMAIL);
/* Do some work */
Message delivery = Message.obtain(...);
replyTarget.send(delivery);
}
}
This all works fantastically well. I can send tons of operations from several different applications to the same service and they all process and send their response to just the right place. However...
I noticed that if the application ran long enough and with enough activity it would crash with anOutOfMemoryError
. Upon looking at the HPROF data in MAT, I noticed that all these operations where staying in memory, and they were held hostage from the Garbage Collector because of theMessenger
. Apparently, the Messenger
instance is creating a long-term native connection to Binder that counts as a GC Root, which is keeping each "Operation" object in memory indefinitely.
Does anyone know if there is a way to clear or disable the Messenger
when the "Operation" is over so it doesn't create this memory leak?
Is there perhaps a better way to implement the IPC to the Service
in the same fashion, so that multiple disparate objects can make a request and get a result asynchronously? I'm not convinced that just switching to using a bound service implementation will solve this issue as I would will need the Messenger to process the callback.
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
No comments:
Post a Comment