I'm writing my first Android application and trying to get my head around communication between services and activities. I have a Service that will run in the background and do some gps and time based logging. I will have an Activity that will be used to start and stop the Service.
So first, I need to be able to figure out if the Service is running when the Activity is started. There are some other questions here about that, so I think I can figure that out (but feel free to offer advice).
My real problem: if the Activity is running and the Service is started, I need a way for the Service to send messages to the Activity. Simple Strings and integers at this point - status messages mostly. The messages will not happen regularly, so I don't think polling the service is a good way to go if there is another way. I only want this communication when the Activity has been started by the user - I don't want to start the Activity from the Service. In other words, if you start the Activity and the Service is running, you will see some status messages in the Activity UI when something interesting happens. If you don't start the Activity, you will not see these messages (they're not that interesting).
It seems like I should be able to determine if the Service is running, and if so, add the Activity as a listener. Then remove the Activity as a listener when the Activity pauses or stops. Is that actually possible? The only way I can figure out to do it is to have the Activity implement Parcelable and build an AIDL file so I can pass it through the Service's remote interface. That seems like overkill though, and I have no idea how the Activity should implement writeToParcel() / readFromParcel().
Is there an easier or better way? Thanks for any help.
EDIT:
For anyone who's interested in this later on, there is sample code from Google for handling this via AIDL in the samples directory: /apis/app/RemoteService.java
Besides LocalBroadcastManager , Event Bus and Messenger already answered in this question,we can use Pending Intent to communicate from service.
As mentioned here in my blog post
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:
(RefreshTask.REFRESH_DATA_INTENT is just a constant String.)
In my listening activity, I define my BroadcastReceiver:
I declare my receiver at the top of the class:
I override onResume to add:
And I override onPause to add:
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 regist a receiver to listen for a broadcast sent from localservice inside your app, reference goes here:http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
The other method that's not mentioned in the other comments is to bind to the service from the activity using bindService() and get an instance of the service in the ServiceConnection callback. As described here http://developer.android.com/guide/components/bound-services.html
To follow up on @MrSnowflake answer with a code example. This is the XABBER now open source
Application
class. TheApplication
class is centralising and coordinatingListeners
and ManagerInterfaces and more. Managers of all sorts are dynamically loaded.Activity´s
started in the Xabber will report in what type ofListener
they are. And when aService
start it report in to theApplication
class as started. Now to send a message to anActivity
all you have to do is make yourActivity
become alistener
of what type you need. In theOnStart()
OnPause()
register/unreg. TheService
can ask theApplication
class for just thatlistener
it need to speak to and if it's there then the Activity is ready to receive.Going through the
Application
class you'll see there's a loot more going on then this.You may also use
LiveData
that works like anEventBus
.Then add an observer from your
Activity
.You can read more from this blog.