Context
I'm working on a screen filter app (like f.lux) for Android. I'm currently working the feature to gradually fade in the filter as the sun sets. The state does not matter when the screen is off, but when the screen is on, it's important that the fade progress be correct (or immediately updated).
Technical requirements
- I want to fire a series of intents at semi-regular intervals.
- When the screen is off, they can be ignored / discarded, except:
- when the screen turns on, the most recent intent must be fired immediately.
- I do not want to drain the battery unnecessarily.
Obvious solutions and why they don't work
- I could use
AlarmManager.setInexactRepeating
, which is supposedly the most energy-efficient of the alarms, except:
Your alarm's first trigger will not be before the requested time, but it might not occur for almost a full interval after that time.
I think this implies that the first trigger will necessarily happen within the first interval, meaning the device will be woken, causing unnecessary battery drain.
- I could use
AlarmManager.set
to schedule the first alarm. When it goes off, I could update the screen, then schedule the next alarm. This would work, but would wake up older devices (without Doze) on each alarm, instead of waiting until the screen turns on. It's also using AlarmManger as a timer, which the documentation explicitly recommends against:
For timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Okay, so,
- I could set a single alarm to starts up a
Handler
, which would update the UI periodically. But wait: this relies onpostDelayed
, which says (emphasis mine):
Time spent in deep sleep will add an additional delay to execution.
I think that means, when the device wakes up from sleep, the next update might not happens for a whole interval. Am I reading this right? Forcing the user to wait a minute or two before the next update is a deal-breaker.
CountDownTimer and ValueAnimator both use this method in their implementations, so if my interpretation of Handler is right, they're both out.
I could use a handler-based method and also receive events when the screen is turned off, at which point I'd cancel the existing animation, then start a new one. This looks to be the best solution, but it seems like there should be a simpler way to do it.
Conclusion
There are a ton of other SO questions on this topic. Everyone and their mother recommends using a Handler, but there's absolutely no information about how it behaves when the device goes to sleep, aside from the quote above. It's really weird that (apparently) nobody else has run into this issue -- am I doing something really unusual, or missing something basic?
Can anybody provide insight about how Handler.postDelayed
really behaves when the device goes to sleep, and recommend what I should do in this particular instance?