I want to use a started (foreground) service to manage a network connection that should persist when the user leaves the application for a short time, and that the user should be aware of (so he can return to the app and maybe disconnect). This service will only ever be used locally by activities in the same process.
Maybe it's just because I am new to Android, but I find it unnecessarily difficult to bind to this service in every activity that uses it - in particular, the asynchronous nature of binding, which only really seems to be necessary for accessing services in a different process. Is there any indication against just accessing the started service through a static variable instead?
Maybe I'm understanding your question wrong, but there is no need to bind to the started Service from every Activity. Instead, you could simply start the Service from wherever you need to interact with it. This calls the onStartCommand() if the Service is already started. You could include an extra with the Intent that starts the Service to distinguish between the first start and subsequent ones.
Of course - this addresses the use case where you do not want to have a client-server mode of interaction between your activities and the Service - that scenario requires binding and if you really need binding, then you need to bind from every component that needs to be served by the Service.
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 curious to know why would you use Bound Service for 2 way interaction between Activity and Service when you can do the same kind of interaction with Started Service using local broadcasts and receivers defined in both Activity and Service
It will be helpful to know the pros and cons of each implementation.
I couldn't find any clear answer to this anywhere.
Using a bound Service is much more flexible. You can define methods on the Service (using AIDL) that return immediate results (synchronously), which you cannot do using LocalBroadcastManager. Using LocalBroadcastManager requires that you use your Service in a completely asynchronous way. This decouples the initiation of a service action with the return of the results (callback) which can make your code more complicated and more difficult to understand. Asynchronous use has some benefits, and there are places where you should use it, but if you have a bound Service you can choose exactly when to use synchronous calls and when to use asynchronous callbacks.
Also, the use of AIDL allows you to exactly describe the signatures of the services's method calls. If you use startService(Intent), you cannot guarantee that the caller will provide the correct arguments in the passed Intent, so you need to rely on the caller to "do the right thing" and/or you need to add a lot of additional argument verification.
Don't forget the comment from #CommonsWare about how LocalBroadcastManager only works if the Service is running in the same OS process as the rest of your app (which makes it unsuitable for programming things like system services, which are not running in your OS process).
A service is a component that runs in the background. It works to perform long-running operations without needing to interact with the user For example, a service might retrieve data over the network without stopping or blocking user interaction with an activity of an app or user may play music in the background while the user is in a different application. A service can be of two types or states:
Started: Once started, a service can run in the background indefinitely, even if the component which is started, is destroyed. A service is started when an app module or component, such as an activity, starts it by calling startService(). For example, retrieving contacts from phone book using service when Splash Screen starts.
Bound: A bound service offers a client-server interface that allows components to interact with the service, get results, send requests and even do so across processes with interprocess communication (IPC). A bound service is bound, when an app component binds to it by calling bindService().
From what I can tell, a Service can only be accessed from an Activity via an IBinder, Messenger or AIDL.
Why can a service instance's methods not be directly called by, for example, an activity?
For example, when the service is started, have the service save its instance in a singleton which would then be accessed by Activitys, allowing them to directly call the service's methods?
From what I can tell, a Service can only be accessed from an Activity via an IBinder, Messenger or AIDL.
That would depend upon what you define as "accessed". startService() can also be used to direct the service to perform some operation.
Why can a service instance's methods not be directly called by, for example, an activity?
Android's component model is designed around loose coupling and replaceable implementations, where the replacements may be local or remote.
Moreover, a service should only be running when it is actively delivering value to the user. As such, there will be plenty of times when the service is not yet running, and the activity would need to start or bind to the service anyway.
For example, an IntentService should only be interacted with via startService(), as the IntentService will only be running while there are commands (supplied via startService()) to be processed.
Finally, the primary role of a Service is as a marker to the OS, letting it know that the process is still doing work, even while it is in the background. A pattern of "let's stuff the Service into a singleton" suggests that you are using the service in cases where the object in question does not necessarily need to be a Service. Just because an object is a singleton does not mean that it needs to be a Service. Hence, you need to sit back and ensure you know exactly why you are using a Service in the first place and whether that is best for the user.
For example, when the service is started, have the service save its instance in a singleton which would then be accessed by Activitys, allowing them to directly call the service's methods?
There's nothing stopping you from doing this. I wouldn't -- I'll use startService() and event buses for communications. And, while it is technically possible to do what you want, whether it is sensible and reliable depends entirely upon the use case of the service and the communications with that service.
I'm creating an application that connects to an XMPP server on Android. I want to keep the connection on till the user logs out.
Should I use a regular Service or a Bound Service to keep the connection on?
Any tips, advice and helpful information are welcomed.
I like this explanation:
Started services are easy to program for simple one way interactions
from an activity to a service, however, they require more complex and
ad hoc programming for extended two-way conversations with their
clients.
In contrast, bound services may be a better choice for more
complex two-way interactions between activities and services. For
example, they support two-way conversations.
So, as you said, If you want to interact with the service use bound service. With started services (or intent services) you could do it, only it would require more complex programming.
(by Douglas Schmidt: https://www.youtube.com/watch?v=cRFw7xaZ_Mg (11'10'')):
Here is a summary that helped me understand (thanks Doug):
Finally, one last link that helped me also:
http://www.techotopia.com/index.php/An_Overview_of_Android_Started_and_Bound_Services
Started services are launched by other application components (such as an activity or even a broadcast receiver) and potentially run indefinitely in the background until the service is stopped, or is destroyed by the Android runtime system in order to free up resources. A service will continue to run if the application that started it is no longer in the foreground, and even in the event that the component that originally started the service is destroyed
A bound service is similar to a started service with the exception that a started service does not generally return results or permit interaction with the component that launched it. A bound service, on the other hand, allows the launching component to interact with, and receive results from, the service.
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely.
If all the code exists in one activity from user connected to user logout then go for bound service
But if it is code exists in multiple activities try with service
I found out the difference between the two and when to use it. If you want to interact with the service (for example send arguments etc), use bound service and it return the service object in the onServiceConnected method (where you can call methods in the service). You cannot interact with a regular service (from another class)
I have a Networking service that i want to use as a Service. It's a local Service since it's not valid anymore once the application process is dead and no Other applications need to access it.(or should...).
I was pondering if to use the IBinder interface with local reference to the class and decided not to, for the moment.
I have the following issues:
if the service dies, and i know it can during request processing, it's an issue for me, first i've seen it, the process wont die until the net request returns (then the thread dies gracefully), unless kill -9 is used on the process... then i'm not sure what android does with the connections. I'm not sure what's the approach i should take here.(it will be true though even if this was a local thread and not a service...)
if i want the service to listen on a callback and call it once the network processing is done, i'm in a problem, no instances can be passed on using Intents. So i need some other solutions, all the ones i though of sounds bad to me: A. use IBinder to get instance of the network service class then i can call one of it's methods and pass on an instance, this will work since they all run in the same process, BUT requires me to use Async way to get a Network instance which is not so suitable for me. B. Use static member in the Service i can access, then what to i need the service for ? C. use intent to send parameters only to the service, the service will compose a Request out of it and put it in the queue, then once done will send a response using intent which will encapsulate the response (which might be long!) and will also contain the name of the calling class as a string so all the Receivers will know if it's for them or not - BIG overhead of encapsulating data in Intent and search in all the receivers for the right one to get the response.
I don't want to use the service as a local running simple thread since i'm afraid if i'll run it in the root activity i will have to use static container so it will be visible in each activity and if the root will be destroyed for some reason it will take all the service with it, even if i start new task and the process is still alive...
Anyone got some nice ideas on how to approach this thing ?
Eventually i gave up on the service.
The reason to not use the service But to extend Application object and keep the networking class as a member of that Application object, it is started when the application is created, before any activity is created,and it is shut down before the application draws it's last breath. I know application onTerminate might not be called at all times, but if someone will call kill -9 or equivalent on my Application and the process will die killing the application with it, i'm all set as my Service will be destroyed anyway.
The reasons i gave up a service were:
i have a way to keep a worker thread running during the application life cycle.
Since i have and for future planning will have only one application it will still work in the future.
Since It's not connected and started with any specific Activity it wont be affected by their death or by their creations.
it has a context that will last through the lifecycle of the application so i CAN use it to broadcast events using intents.
when the application dies my service dies with it. unless kill -9 and then the system will kill all threads related to the application, mine included, so i'm still good.
Every activity can use getApplication() and cast to my Application object and get the service.
So no need to use binding and complicate my code with it, no need to think of how to start or end the service, if i'd made a service most chances i'll be starting it from the Application anyway (or the root activity), so i think for me and my app this is the best option.