I need to grab a service synchronously in Android. I'm sure it's already running, I just need to access it in my adapter. Should I just pass a reference once the service becomes available, or can I use something to the effect of context.getService(...) to get it? What is the recommended solution?
I believe you have an activity where the adapter is created and destroyed. Therefore the adapter's lifecycle should match the lifecycle of your activity. The conclusion would be to pass a reference of the service to the adapter on its creation, as it is the activity that binds and unbinds the service. :-)
What you are interested in is the concept of making a bound service. Take a look at the Local Service Sample example on the Service SDK page:
http://developer.android.com/reference/android/app/Service.html
This example shows how to bind to a service you create so you can get a standing reference to it and make direct calls to it while you are bound. When you bind/unbind to a service in this fashion, you also do not have to worry about calling start and stop explicitly. The service is only running as long as there is at least one component bound to it.
Hope that helps!
Related
I have a service, I need to communicate to with it (one service - many fragments/activities). There are two options for this:
Have a singleton that controls the service - starts it and then binds to it (using the app context)
Have a singleton that controls the service - starts it, the service when ready registers back as a delegate to the singleton (in a WeakReference)
Solution no 2 seems simpler to me, but whenever I read about communication with services there is the concept of the bound service.
Is there any benefit of having a bound service instead of the service registering itself as a delegate (and unregistering with onDestroy)?
Edit 1: The service is to keep the communication alive, it's expensive to set up a new communication channel. Even if no one requested any data it should keep the channel alive (heartbeat).
The service is foreground, it should run even if the activity that requested the data gets killed by the system. The next time it is created the data will be there.
The data requested by one screen might be useful for some other (therefore has to be stored in a singleton).
Bound and unbound services are both usable patterns and you should pick whatever pattern is better for you use case.
You should pick bound service if you want your service to have the same lifecycle as the components that bind to it. If you need an independent service use an unbound version.
The only benefit of one approach versus another is the simplicity of implementation.
In you case, I think you need the service only while there are running activities and fragments, then the easiest way, in my opinion, would be to make a bound service and make every activity bind to it. With that, you'll get a simple communication interface between you activities (and fragments, since they have access to containing activity) and your service.
The benefits of this approach are:
the service will stop itself if all activities unbind and start itself when first activity binds to it.
you won't need to track all running activities in the singleton and manually unbind
you won't need to maintain a singleton manager, less code -> less bugs
sometimes onDestroy can be skipped by the system and you can leak the service with the 2 approach.
Since you need your service to be running the correct option will be to use a started service and make each activity bind to it when needed. It's a common pattern.
Started service will run until you explicitly stop it or it stops itself, you can have a singleton manager that will be responsible for that.
But at the same time you can communicate with the service from your activity using binding.
So basically comparing with the first suggested approach, you'll need some instance that will start and stop the service, but the communication between activities and service will be the same - using binding.
Yes, using a bound service in Android is a much better option when communicating with Views like Activities/Fragments. This is because of the following reasons,
It runs synchronously.
You can have more control on the service data when to show on UI thread of the view. You can choose when to call it in async/sync way.
LocalBroadcastManager only runs Asynchronously.
I am trying to dive deep into service architecture.
Just for testing purpose I am creating music app.
Without doubts music should be played in service, but what kind of communication to use ?
As far as I know service can be bound or started (or both at the same time)
Firstly, I need to play/stop/pause/set source...
Secondly, I need to notify UI if music player is opened about events like progress, buffering...
Here my thoughts about this.
I think about mixing bound and started service.
As far as song can be set only from UI as well as paused/played/stopped/seek I choose communication with service from UI using binder. (Bound service inside activity and get binder back to communicate with service)
Notifications like track completed, next track , current track position coming from the service. I decided to use Broadcast receiver to send such notifications, because it can be multiple interested components.
So my question are
What is the best choice of communication (bound or broadcast) for music player service ?
How does System knows what kind of service is ? I mean that even if the service is bound I need to call startService method at first and than bind it. Does it mean that if even one bindService method was called it is considered as bound service and it would be killed when unbind method is called ?
Does LocalBroadcastManager make sense in communication with service ? As far as LocalBroadcastManager is local for each app, why not to use bound service than ? Global broadcast makes sense in case other apps are interested in events.
Please help to understand this mechanism.
Best choice of communication is using both LocalBroadcasts as well as Binder methods as per your requirement. If you want to do something in service from your bound component like activity then you should use binders. If you need to send result back to application you should use LocalBroadcast.
There is one more option available to use messaging. In this case both activity and service use same ibinder hence two way communication is easy. You can send message from activity to service and service to your activity
In this point you are wrong about starting bound service. You don't need to call startservice in this case. Just a call of bindservice method is required.
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
you can bind multiple components to this service. When all of them are unbound then service will be stopped.
Yes LocalBroadcastmanagers make sense. Lets say you want to broadcast something in your app. There are 4-5 components that you want to update.How will you achieve this. Hence the use of localbroadcasts is a good feature.
For example lets say there are two services starting from different activities and second service starts its work when first service has done its work. So, only way to achieve this is send a broadcast and second service will be registering for this broadcast. Hence it will receive it.
Yeah. Services are pretty hard to understand.
There are some things that are easy. A bound service is always started with a bindService method. A started service is always started with a startService method. You do not need to start a bound service, or bind a started service.
A lot of what follows is gross generalization...
Started Service
A started service is nearly useless, unless it is an IntentService. IntentServices are pretty good tools for running asynchronous tasks. You send them a small bundle of parameters and they go off and do whatever those parameters indicate. They are like void methods in that one expects to use their side-effects, not a return value.
Bound Service
A bound service is harder to explain. Although the metaphor breaks down on careful examination, a bound service something like a singleton factory. It is, for instance, a way of providing a single object, with is single state, to all of the Activities in a application. Among its interesting features is that, as long as the service that provided the singleton object is bound, the hosting process is less likely to be killed off. Note that, the "singleton" object that the bound service provides has little to do with the service that provides it. Unbinding the service does not invalidate it.
Bound services are also the main means of doing inter-process communication, in Android.
What should you do?
Well, that's a pretty general question. Here's a thought. Putting your music player in a service makes a lot of sense. If the communication to it is mostly one way -- commands to the service -- there is a chance that you can do it with an IntentService. Until there's a specific reason to do something more complex, an IntentService has the advantage of being simpler.
There are several ways to connect to Service to Activity. I am only interested in local service and my LocalService will stand there untill user stops it(which also means end of app). I might know things wrong, if so please correct me.
On the reference page, it is stated that in order to use methods of local service directly, we should use ServiceConnection. After binding, we can have a reference to LocalService class, and we can use methods of this LocalService directly. AFAIK the methods we call using this reference run on main thread with relevant Activity.
The thing that confuses me, what if I use skeleton structure and access LocalService's methods by directly its static reference (ie. by LocalService.getInstance()). Well, I have already used it and did not face any problem, but still I am not sure which one is better, and why.
Thanks in advance. I might add additional info if requested.
edit:
In my previously mentioned solution, no activity is keeping a reference to the LocalService.
It is used to
start some LongRunningAsyncTasks(which are all halted and reference-nullified before service stop),
update the app Notification,
get getFilesDir(),
to keep an enum value (whose reference is not kept elsewhere, it is just used for comparison) in order to access from everywhere(not worthy of using SharedPreferences).
show some toasts
aware of static references of activities and services because they can be a reason of memory leak. if you don't want your service run in main process, then extract it into another process and work with service connection.
If you don't need any feedback from service, then just don't use connection and simply use startService() with several commands which will be executed in onStartCommand() method of the service.
If you need feedback from service, but not frequently, then use startService() and feedback from service with sendBroadcast() or through Handler class.
If you need feedback frequently (for example update slider of media player), then it's better to use service connection.
Remember that your service can be killed anytime without executing method onDestroy() and without any notification, that's why keeping static reference is not good idea.
It appears from what you are saying that you probably don't need a Service at all. Looks like you are not doing any long-standing task in your LocalService. If that's the case, you can as well use AsyncTask or Handlers and be done. The motivation to use a Service (Local or otherwise) is to do some long standing task inside it and not stall the main UI thread. If your tasks are not gonna take up too much time, then you don't need a Service.
The Service does run on the main thread by default. Unless it's an IntentService where a worker thread is created for you automatically and all tasks are queued and handled one at a time in this worker thread. Otherwise, it's your responsibility to create a separate thread for your service tasks.
So, first analyze if you really need a Service. If your task can quickly get executed, then don't bother having a Service even.
Hope that helps.
So what I'm trying to do is just updating an activity's views in intervals like, say, once per second. In this specific case a handful of buttons, and all I want to change is their text. I've read quite a few questions here addressing the same problem, but I seem to be stuck a little more than other people, and I'm going to blame that on my restricted experience with Android (which actually means, I did not understand the solutions proposed, or was unable to identify the core ideas in the sample code, and that this is actually the first time I'm trying to program for Android).
Since I would like a service to own the data (and its creation), I thought of a callback to the activity, and that's what I've been trying got get my head around for the past few hours. What I do have is a service with onCreate(), onStartCommand() and onDestroy() and basically, that's fine. I registered it in the android manifest file, and succeeded at bringing it to life (I'm logging the lifecycle methods).
But how do I get to
have the Views updated frequently with the data from the service
give the service certain information it depends on (like notifying it of a button event)
Thanks for your help!
Read about Binding to a Service from the official Android docs.
It should answer all of your questions.
Basically, the idea is that you "bind" to a service, and doing that gives you the service object. From there, you can just call the service's methods directly. In your case, you'd probably want a method declared in your service called notifyButton1Pressed() or something similar.
To refresh the Activity's views in an interval, use a TimerTask and a Timer. Those are pretty self-explanatory if you research them via Google.
In order to update your activity from service, you have to register an BroadcastReceiver in your activity. In the receiver you do your update, and in the service, you have to sendBroadcast to your activity. And information between activity and service you could send through Intent which is sent by sendBroadcast.
There is actually a pretty simple way to update an activity from within itself using a Timer and a android.os.Handler. The idea is to give the activity an interface (e.g. IUpdateable) that exposes an update method. Then extend the TimerTask to take (Handler, IUpdateable) as arguments and keep references to it. In the TimerTask's run() method, call e.g. updateableActivity.update(). In the activity, instantiate a Timer and schedule new UpdateTask(new Handler(), this);.
This way you have an actually reusable approach (using an interface makes this easy to implement in any activity). If this was unclear, have a look at this gist.
I'm developing an app with a service that forwards calls to a web-service, and a few activities that place those calls. The activities need to process the results of those calls. For example, I have a writeComment method on the service, that accesses the web-service and returns some information about the newly written comment.
Right now I let the Activity take care of all the threading. The Activity binds the service, and then uses an AsyncTask that calls the bound service's writeComment method.
All works well as long as the Activity isn't stopped while the AsyncTask is running. If it does (easily happens when flipping the phone), the AsyncTask dies a violent death when trying to update the UI in onPostExecute. I'm not entirely sure how to fix this - I do need to let the user know the server has been updated.
If I go the other way around, and register a callback with the Service, I'm still a bit stump, because I need to notify the Service the Activity has changed - I need to tell it not to notify me in the first Activity's onDestory, and reregister in the second Activity's onCreate. And I need to handle the case where the asynchronous task completes after onDestroy and before onCreate.
What is considered Best Practice in this case?
Thanks,
Itay.
My intuition tells me to let the service handle the threading. Services are far less transient (although still transient to some degree) than activities and therefore you'll have less issues of threads trying to interact with a Context (be it an Activity or a Service) that's no longer there. Have you looked at the IntentService class? It handles a lot of the threading for you.
In my app, I have a long-running service and Activities that need to render data in the service. The service also pings the Activities when there is a change but the Activity can also query the service. The way I approached this was two-fold.
Firstly, I bind my activity to the Service in order to send messages from Activity to service.
Secondly, the Service sends notifications with Broadcasts and the Activity listens for those broadcasts. I set that up in the Activity onResume and tear it down in the onPause. I think this is the part that you're missing.