I have a service which I want to make sure does NOT stop() when there are no longer any activities bound to it.
I understand that startService() is used to achieve this, but is it okay to call this from within the service's onBind() method?
Calling it from the activity seems like a hack to me, because the service know's best whether it wants to hang around after onUnbind().
The activities indicate the current state of the service and provide some control, so bindService() seems like the appropriate method to use here.
It should be fine to call startService() from within onBind(). If you have logic in onBind() that can determine that the service needs to stay up even if the client has unbound then that seems to be the logical place to do it.
I disagree with the answer that claims it is not recommended. The architecture you've described is making effective use of encapsulation. Clients only want to bind/unbind and they shouldn't have to know how the service is (internally) implemented. The service should control its own lifecycle.
Calling startService() from onBind() is not recommended. onBind() is meant for connecting to clients, you should not change the behavior.
Before a client wants to connect, let it call startService(), if service is already running, it will have no effect, client object can then bind. service will still be running when clients unbind. If service knows when not to be around it can safely call stopSelf() on itself and exit.
Related
In the bound services documentation, it says
When a service is unbound from all clients, the Android system destroys it (unless it was also started with a startService() call). As such, you don't have to manage the lifecycle of your service if it's purely a bound service—the Android system manages it for you based on whether it is bound to any clients.
However, if you choose to implement the onStartCommand() callback method, then you must explicitly stop the service, because the service is now considered to be started. In this case, the service runs until the service stops itself with stopSelf() or another component calls stopService(), regardless of whether it is bound to any clients.
Does this mean that simply implementing onStartCommand automagically puts the service into a started state when a client binds to it?
I've been looking for a way to guarentee that when a client binds to the service, the service is in the started state. So far, the only way I've been able to do it is by having the client call startService followed by bindService. But if the above is correct, then all I have to do is implement onStartCommand and the client is free to just call bindService.
I agree that the documentation is wrong. Simply implementing onStartCommand() changes nothing. Especially because you don't implement it, you override the method, because there is already an existing default implementation of onStartCommand()
When you bind to a Service, the Service isn't technically "started", it is just bound. onStartCommand() will not be called unless something calls startService().
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.
The original bind/unbind service can be called by client using bindService()/unbindService().
My question is how to unbind service in service side, not called unbindService() by client, probably I should call it unbindClient.
I think the service should know which clients are bound to it, so is there any way to tell the service to unbind a specific client?
Because i only write the service, and i do't know if the client called unbindService() correctly,so i have this question..
A service cannot unbind itself. You can make a started service stop itself with stopSelf() though.
The OS keeps track of all the binding and unbinding behind the scenes. You don't have to worry about object recycling, Android does it for you.
If you have access to client code -
You can call startService() from the client - which will start the service (and not end the Service on exiting the Activity - since only stopService() will close it).
And also, Client could call bindService() - if they want to perform Activity-Service interaction.
On exiting/unbinding the client, the service will still run since startService() was called - Service can perform other operations and then call stopService() which will destroy itself.
If you want to merely limit the functionality that you service returns once it is started and bindService() is called.You could register a client and unregister when you are done with the service.That way binding your service will not have any impact.This I picked from the Remote Messenger Service example in the android website
We have a Service that takes care of several things in one of our activities. We are fairly new to Android and wondering what the perfect moment for binding to that service is. We only need the service for half of the interactions that are possible via the activity. So we have to settle for one of two possibilities:
bind to the Service when we really need it, which would add a fair amount of overhead implementation-wise
bind to the Service in the onCreate() method without the overhead of checking if the service is running, binding it on demand, maybe caching requests made etc.
What would be the "android way" here? Is a running service a lot of overhead or should it only be started when really needed? The service itself is really lightweight.
Personally I prefer to call bindService() in onCreate(), and after finish using it call unbindService() in onDestroy(). Reason for that is bindService() is actually an asynchronous call. which has not been well-documented in the API. When you call bindService(), the reference of binder object you get inside ServiceConnection.onServiceConnected() callback method is not get instantiated immediately, there is a lag in the meantime after calling bindService() and before binder object get instantiated and ready to use. so the most suitable place to call it is onCreate() as we usually do not preform much heavy operations and need use binder object immediately at this stage.
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.