I wonder what conditions must be met so Android stops a Service, besides the obvious, running low on memory.
See, I run a bootstrapping Service, holding a local BroadcastReceiver. The service itself contains a state machine and so I transition from one bootstrapping state to another. Each states transition function starts either an AsyncTask or an IntentService and once it's done, it dispatches an Intent back to Service to let it know that the task was executed successfully. However, during that, the service just stops, and thus the intent is being dispatched into nothing, which is frustrating.
I don't want to use a Foreground Service and I don't want to trick around just to keep my service alive. I also don't want to rely on onHandleIntent() of an IntentService, since the IntentService looses all its states, meaning all members get nulled once ran through, so when stateA is finished and stateB should be kicked off, the whole statemachine is null, all previous states are gone, etc....
I commit the Services context to each IntentService/AsnycTask and I thought, as long as they hold a reference of the service context, the Service wont stop. Sadly, this is not the case...
Do I have to invoke a method on the context while doInBackground() an AsyncTask, just to keep the Service alive or something?
Beside system running out of memory, you can get your process killed if you exceed certain amount of memory with your service(check limitations).
Like with service processes, foreground processes can extend your service's lifespan, but you have no guarantees either.
I think your best shot is making a logic that will go with services in START_STICKY mode(link).
I wonder what conditions must be met so Android stops a Service, besides the obvious, running low on memory.
A service can be stopped by the user at any time for any reason, either by directly stopping the individual service, or (more likely) by terminating the whole process.
Android will stop a service individually if it crashes. More commonly, it terminates the entire process to reclaim that process' memory for other uses.
I run a bootstrapping Service, holding a local BroadcastReceiver
I doubt anyone but you knows what "bootstrapping" means in this context.
Each states transition function starts either an AsyncTask or an IntentService and once it's done, it dispatches an Intent back to Service to let it know that the task was executed successfully.
Using an AsyncTask from a Service is frequently pointless. You do not want to do stuff on the main application thread in a Service, and the point behind an AsyncTask is to do some work on the main application thread (e.g., onPostExecute()). Use a Thread.
Using an IntentService from a Service is pointless and wasteful. You already have a Service -- it's doing the "bootstrapping". You do not need another Service. Use a Thread.
However, during that, the service just stops, and thus the intent is being dispatched into nothing, which is frustrating.
More likely, the whole process is gone.
I commit the Services context to each IntentService/AsnycTask
I am not completely clear what "commit" means here, but if you are passing a Context (Service) to another Context (IntentService), that is a serious code smell.
as long as they hold a reference of the service context, the service wont stop
No. Moreover, none of that stops Android from terminating your process.
Do I have to invoke a method on the context while doInBackground() an AsyncTask, just to keep the Service alive or something?
No, you need to keep your state machine persistent (a.k.a., a file), so that if your process terminates for whatever reason, when you next run again, you can pick up from where you left off.
Related
I have seen some postings on this subject, but none of them have satisfactory answers.
Assume that I start a worker thread from my main (one-and-only) Activity, in its onCreate() method. Then I call finish() to cause the Activity to terminate.
At that point, the task it belongs to gets destroyed (since there are no longer any Activity in it). The app (and the process running it) may continue to exist, however, in empty "skeleton" form, so that it can be restarted quickly if desired (although it would be highly susceptible to being killed by the system).
Assuming the above is correct -- when is the worker thread killed? Is it only killed when the system actively destroys the process?
In my case, my worker thread exists as a listener for a Bluetooth connection; when received, it will fire up the desired Activity again. In this situation there is no actively running component (Activity, Service, ContentProvider or BroadcastReceiver). It seems to me that this should work, except that something is killing my worker thread.
I am aware that I could do this (and with less pain) by using a background Service. However, I'm curious about why this isn't working.
Thanks,
Barry
when is the worker thread killed? Is it only killed when the system actively destroys the process?
-> the worker thread is skilled after all its code in run function executed. It still run even when your activity is destroyed.
In my case, my worker thread exists as a listener for a Bluetooth connection; when received, it will fire up the desired Activity again. In this situation there is no actively running component (Activity, Service, ContentProvider or BroadcastReceiver). It seems to me that this should work, except that something is killing my worker thread.
To make it works, You need to have a background service in this case and make a soft/weak reference to your service from your worker thread or more simple, using EventBus to start any component from your Service as:
EventBus.getDefault().post(new BlueToothEvent()); // call in your worker thread
// do something in your service
onBlueToothEventFired(BlueToothEvent e);
Android App lifecycle has a nice example that is very on topic:
A common example of a process life-cycle bug is a BroadcastReceiver
that starts a thread when it receives an Intent in its
BroadcastReceiver.onReceive() method, and then returns from the
function. Once it returns, the system considers the BroadcastReceiver
to be no longer active, and thus, its hosting process no longer needed
(unless other application components are active in it). So, the system
may kill the process at any time to reclaim memory, and in doing so,
it terminates the spawned thread running in the process.
In short, its really not very predictable if you thread would get a chance to run until termination or process will be killed beforehand, you should NOT definitely rely on any order/behavior.
Worth mentioning separately that its fairly easy to leak your activity along with thread even if you finish() it, but if its your last/only activity it does not change the picture
When you start a thread, it is independent of the parent that started it. In your case, it is your application activity. This means that until the Run method has been fully executed, your thread will live.
If you exit the application (and therefore call the activity's onStop method), the thread will still exist, and you will cause a memory leak. It will eventually get killed by the system if you run out of memory.
Since you mentioned that you created a listener to listen for a Bluetooth connection, your thread probably dies before it receives any event (It is impossible for me to know without any code snippet). It might also crash which would be ending the thread.
There is one main (also called UI) thread in Android. That is the only thread your app uses, unless it starts one explicitly via Thread.start(), AsyncTask.execute() etc. All Activities, Services, BroadcastReceivers, etc run all of their lifecycle methods on that main thread. Notice I included Services- a Service runs on the main thread unless it starts its own Thread (the exception to that is an IntentService, which does run on its own Thread).
A Thread you create continues until the Runnable its passed returns from its run function (or of course the process is terminated). This can live past the end of the Activity/Service it was created by. However such a Thread would still live in the original instance of the component, and would not be able to access variables of a new instance if one was restarted without a lot of special work (see Loader pattern).
I have an activity that contains an Instance of FileObserver. I start watching in onCreate and stop watching in onDestroy of the activity. So what happens if onEvent is doing some operation and the activity is destroyed (user presses back button)? Does my onEvent continue to finish what it was doing? Basically I am wondering whether onEvent should start a service or handle its business itself.
Does my onEvent continue to finish what it was doing?
At least briefly, yes. FileObserver is not tied to a specific component's lifecycle, like that of an Activity.
However, once your app is no longer in the foreground, your process can be terminated at any point, to free up system RAM for other apps. Android is not going to pay any attention to your FileObserver and its onEvent() processing when this occurs, by default.
If you expect the work to happen quickly — say, under a second — you should be able to keep it where it is.
If, however, the sort of work that you are doing is more substantial, I would consider having a service do the work. Per our prior discussion, while the FileObserver should not be in an IntentService, the work triggered by the FileObserver could be. onEvent() would call startService() to tell the service to go do the work. Services are a signal to the OS that you are actively doing work on behalf of the user, and so your process is more likely to hang around for a bit longer.
Unless the Application is stopped the code in your onEvent will continue to run.
FileObserver.onEvent documentation
This method is invoked on a special FileObserver thread. It runs independently of any threads, so take care to use appropriate synchronization! Consider using post(Runnable) to shift event handling work to the main thread to avoid concurrency problems.
So the only think you need to be concerned with is what exactly you are doing in onEvent. For instance if you are updating UI or interacting with the Activity / Fragment in your onEvent method then this could cause a crash if the Activity goes away.
With that in mind a service will certainly increase the odds that the application does not terminate while you are performing your work.
Service documentation
The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again...
So the bottom line is that a service is more likely to keep your application alive. Event more likely if you call startForeground but in this case you need to be willing to show a notification to the user.
I have an android Service class which has a long running onDestroy. I need to prevent this as it can cause a hang when there are activities running.
It seems some people are happy starting a thread/AsyncTask in the onDestroy method to hold the long running code, though I'm concerned that the threads may be killed. Another solution may be to use startService instead of stopService with an intent that tells the service to start a shutdown thread which calls stopSelf at the end.
Are any of these solutions sensible, or is there another way?
A shutdown Intent is a reasonable way to go here.
Starting another Thread in onDestroy is a bad idea though. It might be called or not called when you don't expect or want it.
Edit: To persist important information neither of these ways is a good idea.
You cannot assure that these methods actually get run before your process is killed. For non-important data you could of course go these ways, but you'd better persist your data as soon as you get it, or at least within a fixed interval (if you have a continous data input).
From the official Documentation:
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here.
This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
And here the Documentation specifcally for services:
Called by the system to notify a Service that it is no longer used and is being removed. The service should clean up any resources it holds (threads, registered receivers, etc) at this point. Upon return, there will be no more calls in to this Service object and it is effectively dead.
(I've included the Activities documentation, because it is more precise)
You should be aware that there is no absolute guarantee for onDestroy to be executed.
It seems some people are happy starting a thread/AsyncTask in the onDestroy method to hold the long running code, though I'm concerned that the threads may be killed.
I would assume that you're trying to either free some resources or send some sort of message to server.
In case of resources there is no need worry - if you'll start new thread it will be killed only together with hosting process (your app). If that would happen - it's ok, system will release resources for you.
In case of server message - that is a bit more complicated. I like your idea with sending command to a Service instead of calling stopService. Other option would be to start another tear-down Service from your onDestroy which will perform long running operation and shut down itself.
I'm fairly certain that it's standard practice to handle asynchronous file downloads using a Service and AsyncTask. That way, you can kill the originating activity and go on your merry way. However, when you don't need the lifecycle management, remote process communication, or other major features of a Service, it seems a bit overkill.
Since a Service is still a part of the same process and lifecycle of the overall Application, why not simply run a background thread within the context of the Application (vs Activity, although not necessarily within the extended Application class)? Is there any reason why this would be a particularly bad idea?
I'm fairly certain that it's standard practice to handle asynchronous file downloads using a Service and AsyncTask.
An AsyncTask is useless in a Service, as you have no reason to do anything on the main application thread in a Service. Use an IntentService for downloads, as it gives you a background thread, plus automatically stops itself when there is no more work to be done.
why not simply run a background thread within the context of the Application... Is there any reason why this would be a particularly bad idea?
Because your app will be unreliable.
While a lot of people focus on the independent lifecycle of the service, that's not why you use a service for something like this. You use a service as a flag to the OS that your process is still doing something.
Once you are no longer in the foreground, Android can terminate your process, at will, at any moment. Particularly if there is a lot of memory pressure, this can be within milliseconds of your app leaving the foreground.
However, Android generally prioritizes terminating empty processes (ones with no running activities or services) and activity-only processes, ahead of processes that contain a running service. Here, "generally" means that processes with services will not live forever, but they are far less likely to be terminated quickly.
Hence, using an IntentService is signalling to the OS that you are still delivering value to the user (downloading the file) and that it should leave your process alone, until either your IntentService stops (because the download completed) or your service runs so long that it's probably lost its virtual marbles.
An Application is not a Service. Every process has an Application instance. Having a download be "managed" by an Application is pointless -- you may as well run a bare thread outside of any Context. And, most importantly, nothing tells the OS that you are doing anything meaningful, and so your process can be terminated as soon as you leave the foreground.
However, when you don't need the lifecycle management, remote process communication, or other major features of a Service, it seems a bit overkill.
Writing an IntentService, outside of the manifest entry, is not significantly more complicated than writing an AsyncTask. Invoking an IntentService is not significantly more complicated than invoking an AsyncTask.
I have some confusion with android service
As per the documentation
It will keep on running in the background on main thread . It doesn't run in a different thread.
My doubt is what is the meaning of keep on running in background . Will it execute the onStartCommand() again and again. I am really very confused with this line (Keep on running in background )
if it will not execute onStartCommand again and again then what is the benefit of Keep on running and if it executes onStartCommand again and again then it is using cpu more and more
Line which confused me is highlighted in the image please have a look
As already noted in a comment, for your particular purpose (monitoring a setting, here: volume), you can follow a non-polling approach which is described e.g. here: Is there a broadcast action for volume changes?
In general, on a modern (though not perfect) environment like Android, there's almost never a reason to actively poll something, because nobody could afford wasting so much resources, and also, you'll always risk to miss events, so you'd be tempted to poll more frequently -- this is a race which your implementation is always going to lose.
Once more, the following statements are plain wrong:
A Service runs on your app's main/UI thread. If you think this is the case then you need to read about the android:process attribute of the manifest's activity tag. Also. even if you do not let your service run in a separate process, the phrase a service runs on your app's main/UI thread suggests that your main/UI thread gets blocked by your service. Of course, hopefully nobody leaves iot art that; it's easy to just process the service's events on your app's main/UI thread and delegate the tasks to worker threads, which is what every sane implementation should do.
With START_STICKY, you can ensure that your service will always be running after it got started. Of course, this is naive and means that whoever claims this has not completely understood the meaning of this flag in conjunction with the description of the process lifecylce for Android Services. Quote: Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory pressure. If you read the section, you will know that Android is going to kill the process with your running service at any time without notice if it needs memory for another task with higher priority and your service is not related to an app which the user currently looks at. In other words, if the system is low on memory and the user opens a spreadsheet which requires most of the system's memory, then the background internet radio media player and all fancy stuff is likely to get killed, period.
A Service runs on the thread of your app and after started it keeps running until it calls finish() or android needs memory.
But the running doesn't necessary means that it is processing something. onStartCommand() is called only when someone calls startService() on your service.
So the service instead of running always it's always in memory ready to be run when needed. The main use of service is to do some processing that keeps running even if you change activities, like a music player that keeps playing when you are changing activity looking for the next music to play.
Edit: On Documentation "A Service is not a separate process....A Service is not a thread. It is not a means itself to do work off of the main thread".
A Service is "A facility for the application to tell the system about something it wants to be doing in the background"
"A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated."
Service Documentation