How to have Android Service communicate with Activity
There are three obvious ways to communicate with services:
- Using Intents
- Using AIDL
- Using the service object itself (as singleton)
In your case, I'd go with option 3. Make a static reference to the service it self and populate it in onCreate():
void onCreate(Intent i) {
sInstance = this;
}
Make a static function MyService getInstance()
, which returns the static sInstance
.
Then in Activity.onCreate()
you start the service, asynchronously wait until the service is actually started (you could have your service notify your app it's ready by sending an intent to the activity.) and get its instance. When you have the instance, register your service listener object to you service and you are set. NOTE: when editing Views inside the Activity you should modify them in the UI thread, the service will probably run its own Thread, so you need to call Activity.runOnUiThread()
.
The last thing you need to do is to remove the reference to you listener object in Activity.onPause()
, otherwise an instance of your activity context will leak, not good.
NOTE: This method is only useful when your application/Activity/task is the only process that will access your service. If this is not the case you have to use option 1. or 2.
The asker has probably long since moved past this, but in case someone else searches for this...
There's another way to handle this, which I think might be the simplest.
Add a BroadcastReceiver
to your activity. Register it to receive some custom intent in onResume
and unregister it in onPause
. Then send out that intent from your service when you want to send out your status updates or what have you.
Make sure you wouldn't be unhappy if some other app listened for your Intent
(could anyone do anything malicious?), but beyond that, you should be alright.
Code sample was requested:
In my service, I have this:
// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));
(RefreshTask.REFRESH_DATA_INTENT
is just a constant string.)
In my listening activity, I define my BroadcastReceiver
:
private class DataUpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
// Do stuff - maybe update my view based on the changed DB contents
}
}
}
I declare my receiver at the top of the class:
private DataUpdateReceiver dataUpdateReceiver;
I override onResume
to add this:
if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);
And I override onPause
to add:
if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);
Now my activity is listening for my service to say "Hey, go update yourself." I could pass data in the Intent
instead of updating database tables and then going back to find the changes within my activity, but since I want the changes to persist anyway, it makes sense to pass the data via DB.
Use LocalBroadcastManager
to register a receiver to listen for a broadcast sent from local service inside your app, reference goes here:
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html