android service notify activity completed best way?

marchinram picture marchinram · Jul 6, 2011 · Viewed 11.3k times · Source

I created a service which syncs data from the web on a background thread and want to notify a list activity when the service has completed so it can update it's cursor? What would be the best way to do this? I'm thinking of sending a broadcast when the service is done but not sure if that's the best way to do it. I need to requery the cursor when the service has finished so I'm not sure if that will work well with broadcast receivers? I haven't done alot of android in awhile so thanks in advance.

Answer

zeitkunst picture zeitkunst · Jul 6, 2011

Use a Handler in your service that registers a client when your ListActivity connects to the service; that is, in your onServiceConnected method in your ListActivity, send a Message to your service that enables you to keep track of connected clients. Then you can simply loop through these clients in your Service and send them a Message when something takes place in your Service that you want to notify your ListActivity about. For more information you can look at code in an on-going project of mine: my ListActivity and my Service stub.

In short, in your MainActivity, start and bind to your service with:

Intent i = new Intent(this, NetworkService.class);
startService(i);
bindService(i, networkServiceConnection, Context.BIND_AUTO_CREATE);

Define a messenger to respond to messages from the service like:

Messenger messenger = new Messenger(new IncomingHandler());

class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case NetworkService.MSG_SOMETHING:
                // do something here
                break;
            default:
                super.handleMessage(msg);
        }
    }
}

And then write your service connection code like:

private ServiceConnection networkServiceConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        networkService = new Messenger(service);
        try {
            Message msg = Message.obtain(null, NetworkService.MSG_REGISTER_CLIENT);
            msg.replyTo = messenger;
            networkService.send(msg);
            log.debug("Connected to service");

        } catch (RemoteException e) {
            // Here, the service has crashed even before we were able to connect
        }
    }

Note that the replyTo is the messenger we just created.

In your NetworkService, keep track of connected clients with:

ArrayList<Messenger> clients = new ArrayList<Messenger>();

and create your handler like:

class IncomingHandler extends Handler {
       @Override
       public void handleMessage(Message msg) {
           switch (msg.what) {
               case MSG_REGISTER_CLIENT:
                   log.debug("Adding client: " + msg.replyTo);
                   clients.add(msg.replyTo);
                   break;
               default:
                   super.handleMessage(msg);
                   break;
           }
       }
   }

Then, when you want to send a message back to your MainActivity, just do something like the following:

for (int i = 0; i < clients.size(); i++) {
    try {
        clients.get(i).send(Message.obtain(null, MSG_SOMETHING));
    } catch (RemoteException e) {
        // If we get here, the client is dead, and we should remove it from the list
        log.debug("Removing client: " + clients.get(i));
        clients.remove(i);
    }
}