I have an Android app, in which Activities fire long running operations that run in the background. These operations interact with the Activities when done. I'm developing a component that handles the Activity/Long-Running-Task coupling, taking care of activities being destroyed and recreated.
Right now that component is implemented as an Android service. The activities call bindService and use the resulting IBinder to start and track tasks. I decided against using startService, because I prefer the richer API possible through a Java interface.
Now the problem. Activity A start ups, binds to the service and calls serviceApi.runTask(...). Activity A is then destroyed (because the user flips the phone, for instance) and recreated as Activity A'. A' then binds again to the service, announces its existence and everything should be running nicely.
Except that my Service gets destroyed. When Activity A is destroyed, it unbinds from the service. Android sees there are no more clients, and kills the service. When Activity A' is created, the service is created again, and I lose everything the old service had.
The only solution I can see is using a singleton for the service. And then it doesn't really have to be an Android service, just an instance that's accessible to everyone. Is that frowned upon in Android? Is there a better design that fits this problem?
Editted: Even if I call startService and then bind to it, nothing guarantees that the service instance will exist as long as the application is running. Android can kill sticky services if resources are low. Killing the service will cause the application to malfunction, and I can't have that.
Even if I call startService and then bind to it, nothing guarantees that the service instance will exist as long as the application is running.
Correct.
Android can kill sticky services if resources are low.
Also correct. All "sticky" means is that Android might restart the service.
Killing the service will cause the application to malfunction, and I can't have that.
It is impossible to create a service that is guaranteed to run forever. For starters, users can get rid of your service whenever they want, because users detest developers who have pointless services that run forever. Writing everlasting services is necessary only in very few cases; otherwise, it's just sloppy programming.
The only solution I can see is using a singleton for the service. And then it doesn't really have to be an Android service, just an instance that's accessible to everyone. Is that frowned upon in Android?
Singletons (a.k.a., static data members) will go away when the process is terminated. The process will be terminated eventually, particularly if there are no active services and none of your activities is in the foreground..
Call startService and in onStartCommand return START_STICKY. It should keep the service going.
You may also want to look into foreground services:
http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)
Yo have to create persistent service. Refer to this manual.
In a few words - don't call bindService, call startService.
Related
I have an Android Library with a service, which I implemented using AIDL. I want a single instance, cross application to be used with other apps. So I have a base app with the service and I managed to make the library for other apps to use the same instance.
My problem comes when I close all apps using the service, because for every app, the on destroy unbinds from the service, but the service is still running.
Also, I'm only using the service by binding, not by startService().
I checked through android studio that the service is running after closing the apps, and the counter I have on the service for each bind/unbind call is 0!. I increment the counter when there is a call to bind, and decrease for calls to unbind. My only way to make the service stop is by opening the base app, which has the service defined and closing it.
Edit: Also noticed that onBind is being called only once, even for other apps that are binding, but the reference for all those apps is still the same service, they share the same information and only one Service is shown in the android studio.
Edit: I've also observed that if one of the apps using the service is the base app, if I close it, the service dies and another one is started, the other apps don't notice the change, they keep using the service as if nothing happened, which is understandable because it's a remote service.
What is happening and what can I do about it?
For the two points being questioned:
I was able to verify what CommonsWare said that the process in which the service is run is still up, but the service itself is not. At first I had a thread running in the service after every app unbound, but after making sure it wasn't up in the end made the service be destroyed.
The second issue, regarding the service being destroyed while still bound with other activities was solved by seeing this link which describes a bug in android that kills services when it shouldn't. My case was simply solved by making my service run in the foreground, which I didn't know was possible.
After some tests I verified the service is still intact as long as any app is bound with it, and that the service indeed is destroyed correctly after no more app is bound.
I am wondering what is the best way to keep a service running while the application is running (may be in background) and then the service stopping when the application has ended (the application in this case has completely stopped, not in the background).
Another sub-question is: How to stop a service when application stops?
I realize one solution is to use BoundServices but is this the best way or good enough?
For example if an activity binds a service and then the system kills the activity and brings
it alive again then how will the service behave? Or are there other issues I am not aware of?
What would be the best way to implement this? Thanks.
Check out http://developer.android.com/guide/components/bound-services.html.
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.
You have two options to start the service:
1. bindService() to activity
2. startForeground() and bind while it runs
Option 1 will only run as long as the activity is in view and the runnable active. (example use would be to use service to download a file)
Option 2 will run as long as the application is running (even when the activity is in the background) This option requires that your service be listed in the notification bar.
You can have a service stop itself by calling stopSelf(int) (I dont think this works if a activity is currently bound) or you can call stopService() from an activity.
As for the system killing the activity question.... Without knowing what your service will be handling its hard to give advice on how to handle this situation. For the most part a service running in the foreground will be the last resource the system will try to reclaim. If the system kills the activity the services onDestory method will be called where you should do some clean up so that the next time it starts you can continue in a safe manor.
http://developer.android.com/images/service_lifecycle.png
It's my understanding that Android services are supposed to be singletons - no more than one class instance running at a time. So you're supposed to start them via intents, as opposed to
MyService mse = new MyService();
However, in Google's in-app billing sample, that's exactly what they do in Dungeons.java, line 235. So it's obviously legal.
I'm wondering, if I start a service like this, will the framework later recognize that it's running? In other words, if I try to call startService() on the same service later on, will the framework recognize that an instance of the service already exists and dispatch startService() calls to it?
I don't know what example you are referring to. But you absolutely positively cannot instantiate an Android component (Activity, BroadcastReceiver, Service, Provider) yourself using the new keyword. These components can only be instantiated by the Android framework, as the framework needs to set up the Context of the component.
There is (unfortunately) nothing stopping you from writing Service s = new MyService();, but it will do you no good. Android will never call any of the lifecycle mathods on this Service and any calls you make to methods of the Service will probably fail spectacularly because the instance has no Context.
If you instantiate the service directly instead of using intents that guarantees the service will run within your Activities process. If that activity should be killed then down goes the service too. Is that a bad practice? Well it depends on what you wanted. If you need that service to live through potential shutdowns of activities then yes that's a bad thing to do. If you don't care or your app can tolerate those shutdowns then it's ok. However, I'd argue if you need a background job running that can be stopped when your Activity stops then you need to use AsyncTask and NOT a service.
I'm developing an Android application that consists of:
a lightweight background service that logs events to a DB
a heavier GUI application that summarizes these events and displays graphs.
I'm having trouble creating the service part, though. The graphic application can use quite some RAM, and when it goes to the background, the OS closes it after some time of not being used.
The problem is, when the application gets shut down, so does the service. This is bad because this keeps me from recording further events. I don't care if the application gets terminated, but the service needs to keep on running.
I have tried numerous ways to keep the service alive, like having it use threads or a differently named process than the main app. Nothing has worked, and I have found no help on any of the android developer pages or forums.
Thank you for your advice!
Try to return START_STICKY in your service's onStartCommand(). Also how do you start your service? If you use bindService() with BIND_AUTO_CREATE flag it will be stopped automatically on unbindService(). You should explicitly start it with startService() and stop calling stopSelf(). Than OS keep your process running on the background after activity will be closed. Note: the activity and the service run in one process and it's imposible: "application gets terminated, but the service needs to keep on running". But it is possible to keep the process running without activities, with service running on the background.
Read the detailed info http://developer.android.com/reference/android/app/Service.html.
good luck!
You should use the AlarmManager to respawn your service. You just can't keep your service alive eternally.
Check about the lifecycle : http://developer.android.com/guide/topics/fundamentals.html
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.