How to manage stopping a Service with a long-running onDestroy? - android

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.

Related

Long running operation inside onEvent of FileObserver

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.

Why is my Service stopping?

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.

Force close on second start of application

I am developing an Android application, and when I start my application 2nd time I am getting force close error. Following is my logcat:
06-07 16:08:12.763: ERROR/AndroidRuntime(3293): Uncaught handler: thread exiting due to uncaught exception06-07
16:08:12.773: ERROR/AndroidRuntime(3293): java.lang.NullPointerException06-07
16:08:12.773: ERROR/AndroidRuntime(3293): at com.androidpeople.tab.MobiintheMorningActivity$t2.run(MobiintheMorningActivity.java:209)06-07
16:08:12.773: ERROR/AndroidRuntime(3293): at java.lang.Thread.run(Thread.java:1060)
Your logcat capture is telling you that in your source file MobiintheMorningActivity.java, at line 209, you're using an object which is null. Seems pretty straight forward.
To prevent the application from crashing place try{//insert code} catch(Exception e){//todo when something fails}
On the NullPointer, try debugging your program and locating the null
Huh, I feel that I should give some more useful comments than those stupid answers from Captain Obvious fellows. Usually such problems happen because developer doesn't fully understand Android Application life cycle. When you start application second time, actually you re-starting an Activity, not whole Application, so for example static data may remain from previous activity launch, even you received onDestroy() event for that activity. If you created any threads, they may remain alive (if you don't take special actions to stop them gracefully, which is not often a trivial thing - for example in my case a thread was reading data from InputStream.read(), a blocked call ending somewhere in native code, and it was not possible to interrupt it, either via Thread.interrupt() or via InputStream.close() called in other thread. But it is another story).
So, from design point of view, if you're using threads, you must keep in mind that you may be attempting to start a new thread while the old one hasn't finished yet.
Whole application will be fully destroyed when OS decides so, when it will need to recycle memory. If your app is running some threads in background, the app may be considered alive, even you do not have open activities at the moment, and the app may avoid recycling, causing some sort of memory leak. This is considered as a bad coding style.
In your case the thread seems to reuse some old data, which you probably expected to be re-initialized by Activity re-start. Or you may have another thread concurrently running from previous launch and sharing data with Activity being started second time, and it reads/writes data while you're initializing them in the second start of the Activity, for the second start of the thread.
So you need to make sure that you do not start another thread before the first one quits. You may consider using a Local Service for such purposes, but you would need to launch threads for background activities (to not perform them in main event thread of the application, which is common for services and activities in the same Application instance), or in AsyncTask. A Service simplifies things a bit because it is not interrupted by Activities start/end, so you can somehow handle an async process (in your thread) between activities restarts. So activities should put requests to service to perform long jobs, and query its state from service (or receive notifications, for example via listeners, which quite OK for local services). So, starting an activity, you should check what the server is doing - probably it already performs a job from previous activity start. Your activity may request to stop the job (if you already didn't do so when previous activity finished), and wait for job cancelation, which generally may be not a quick thing, and should be made asynchronously). Of course you may implement the same approach without a service, just in that thread.

Application.onLowMemory() not invloked

I've create an Application class of my own.
I try to debug it and the code stops at Application.onCreate() but does not stop at onLowMemory.
To test the scenario I open a lot of other high memory applications.
What I see is that the debug session terminated (in eclipse) and some of my static variables turned to null - indicates the the process has ended.
Not only did the debug NOT stop # the breakpoint of the method, I've put a Log.e(...) line and don't see it as well.
Any idea of why the method was not invoked?
Thanks.
I don't think that there are any guarantees that this method will ever be called.
From the docs:
While the exact point at which this
will be called is not defined,
generally it will happen around the
time all background process have been
killed, that is before reaching the
point of killing processes hosting
service and foreground UI that we
would like to avoid killing.
Since the point at which it is called is not defined, it could choose to never call it.
In general, Android is free to kill your Application whenever it wants, as long as it is in the background. You should only rely on methods in the lifecycle (like onPause, onStop, onDestroy) that specifically state that they are guaranteed to be called in order to do any necessary cleanup.

Network Service needs to return a callback

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.

Categories

Resources