Home / Blogs / Matt's blog
Android service - why no onStop()?
For the most part I enjoy developing for the Android API. However, there are some very odd quirks that leave me pretty frustrated.
An Android service is pretty much as you'd expect from any kind of service. It can be created, started, stopped and destroyed.
There are callback functions for onCreate, onStartCommand and onDestroy, but nothing for onStop. Seeing as a service can be created but not actively started, I can't find any way of knowing when the service is in this limbo state.
In my particular situation, my service uses handler.postDelayed to run a task every 8 hours or so. I call this during onStart. Now, because Android can stop a service at any point if resources start to become scarce, I have some code that starts my service based on the periodic update of a widget. When you start a service via an Intent, the onStart method of that service is ALWAYS called whether the service is already running or not. This means that postDelayed was being called regularly, causing my task to run much more often than I expected.
My first solution was to not call postDelayed if the Runnable is already in the handler queue, but there's no way of telling whether this is the case. Removing then re-adding the Runnable from the queue every time is not acceptable as it could cause my task to never be started, or to run far too often.
So the next obvious solution is to not call postDelayed if the service is already running... but as there's no way of telling if the service is started, and no way to monitor if it has been stopped, this is unreliable too.
Right now I have no reliable solution, but if anyone has any ideas please let me know!

In my experience, when a service is stopped, it's destroyed as well, so doing cleanup in onDestroy should be fine. However, having a pending postDelayed when a service is stopped is a pretty bad idea, and I've no clue how Android responds to that. My guess would've been it simply removes those runnables along with the service and its Handler.
Anyway doing thinks like this with a constantly running (or rather sleeping) Service, Handler, and postDelayed is quite bad design, and exactly the reason why Android 2.x doesn't support setForeground anymore. It just blocks memory and doesn't do anything useful. Better use AlarmManager for such jobs.
Thanks for your comments. I am assuming that the service is destroyed as soon as it is stopped as I don't really have any other choice.
I've also ditched my use of Handler in the service. When the phone goes to sleep it all goes wrong anyway. I'm now using AlarmManager as you say.. works a whole lot better.
Could you use a file or DB to help?
1. Start service
In OnStartCommand...
2. If no entry, create a time +8 hours in storage (database or file)
3. Set a postDelayed (or postAtTime might be better) to correspond to that value
4. While waiting, stuff might happen that might stop the service. If so when you start the service against, you'll see the entry in storage, so no need to create a new postDelayed based on that.
5. When the delayed action executes, remove the entry from storage.
6. When OnDestroy happens (and, presumably, the Runnable becomes invalid, right?), remove the entry from storage.
I'm pretty new to Android development. :-)