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 on postDelayed, 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?
Related
I'm having trouble deciding whether to run some recurring background work with Alarm Manager or Work Manager:
The work is going to consist of Room Database operations so I'll need access to Dao to complete my work.
It is going to be recurring at fixed intervals (hourly, daily, weekly, monthly, etc.)
I need to set a start date and time for the recurrence intervals.
the work will recur until canceled by the user
If the user is using the app when the work is supposed to be scheduled, I want the work to be done immediately. If the user is not on the app (app is in the background or device is turned off), I don't care if the work is done after the scheduled time as long as it is at least started by the next time the user opens the app.
the work needs to continue as scheduled after device reboots and app restarts.
For recurring background work, AlarmManger isn't suitable. As the name implies, it's intended to notify the system of an event at a precise time. Just like a physical alarm that wakes a person up even if the person sleeps, AlarmManager will wake up the device from doze mode which will result in more power usage. it is suitable for suitations like setting remainders such as for calender events which the users probably set by themselves.
On the other hand, WorkManager is intended to carry out background processing or work that would persist. Workmanager is much more efficient for recurring task especially as it allows you set constraints to determine when it should start or stop the background work.
check the link form the offical documentation on WorkManger:
workmanager architecture
tabular comparison between the two
It mostly depends on how important your task is.
https://developer.android.com/guide/background is a really good entry point to help you choose what you should work with.
WorkManager is the modern, universal approach of handling background work and it fits for most use-cases, it automatically reschedules work after a device restart or an application crash, and it is very efficient in terms of battery usage.
As WorkManager does respect Android's doze mode, it does not guarantee, that the work will be done exactly on time, though it does guarantee, that your work will be done within a certain time frame.
On the other hand, AlarmManager is capable of running work precisely on time. But this means that the device will wake up when your work scheduled with AlarmManager is coming due. This will drain battery and your app will probably show up as battery-draining in the Device Health board.
But as stated in the article above, prefer using WorkManager if possible. AlarmManager should only be used for e.g. a time-sensitive calendar notification.
My application should detect whether the user was sleeping to start itself with a welcome message when the user wakes up and powers up his phone for the first time in the morning, afternoon, or whenever he wakes up, by pressing the power putton and entering the pattern on the homescreen or pin or whatever.
I want to do this by measuring the time the device was used the last time. I presume 8 hours of sleep, so if 8 hours passed since the last switching off, the next time the mobile phone is being switched on, the application starts(respectively a function inside).
The screen going on because of an alarm or anything but user interaction should not count.
I looked at logcat and it gave me the useful information I/PowerManagerService: Going to sleep due to power button. So a PowerManagerServiceListener could be a way. I found https://developer.android.com/reference/android/os/PowerManager.html but it is for actively keeping the display on, not for passively reporting it.
Another candidate is KeyguardViewMediator: onStartedGoingToSleep(2) and KeyguardServiceDelegate: onScreenTurnedOff().
Sure, I could create a polling application, that looks through logcat, but that sounds like a strongly battery draining approach.
Which performance friendly way is there to accomplish what I want?
According to your description, you are interested in a granularity of hours. Then you can schedule a repeating alarm every hour (see Scheduling Repeating Alarms), save the time in a Shared Preference, receive a BOOT_COMPLETED broadcast, compare the times and decide what to do.
However, I guess a lot of users don't turn their devices off, so I would try to find out if the assumption your approach is based on is valid.
You can also try getDetectedActivity() from Snapshot Awareness API and check if DetectedActivity is for example STILL at some specified interval.
I'm developing an application which needs to run small chunks of code frequently (once every two seconds, for example). I've tried to make it work using the simple Thread.sleep() (or android.os.SystemClock.sleep() to avoid interrupts, and finally I've tried with Timer and Handler), but the result is that the time that the program sleeps is random (or it simply doesn't run if I use Timer or Handler as the system discards they messages when the screen is off), as the system goes to a deep sleep mode during screen off.
For example the code works right if I have the phone plugged into the charger, or is playing music (that avoids the deep sleep mode), but when the phone isn't doing anything the time can grow from two seconds sleep up to minutes of sleep.
From https://groups.google.com/forum/#!topic/android-developers/Eqwp8Uiy2f0 seems that the only alternative is to use the AlarmManager to force the wake, but that way will probably cause too much battery drain.
Is there any alternative?
If not, is there any way to detect when the system goes into the deep sleep mode?
It is too late but may be useful for somebody else.
Yes, Timers does not work in deep sleep mode.I think there is no other better way than AlarmManager to run something periodically in deep sleep mode.
Also, as your frequency is just 2 seconds I think you may have to go for exact alamrs (setExact() ) as the regular alarm may not serve you better if your requirement is critical in time. And sometimes even setExact might not capture the wake lock I observed. So you have to acquire your own (PARTIAL_..) wake lock and, do stuff and release the lock.
But is it must that you have to run evvery 2 seconds ?
If not continue using Timers which will continue working automatically after the device wake up.
Take a look at Should I use AlarmManager or Handler?
I'm new to Android and Java programming, so I would like to clear up couple of questions I have.
I've written a background service that verifies something every 10 seconds, and, based on some conditions, it may execute something (or may not). This is implemented using a Timer.
My understanding until now is that the timer in the service will run even when the screen is off, so every 10 seconds, even with the screen off, the timer will fire up.
I suppose that this will have an impact on battery life, though I don't know how much or how to measure this.
Now, I don't need the service to do anything while the screen is off, so I'm thinking about registering the Screen OFF and Screen ON broadcast Intents.
On Screen OFF, the code would stop the timer – or would it be better to stop the whole service? – and on Screen ON it would start the timer (or service).
My thought on this direction is that my application will consume less of the battery than it would otherwise
Please tell me if my logic makes sense
If I'm wrong or if there are better ways to achieve this, please let me know.
Thank you!
I'm trying to run a background task which runs every minute or so for an android application but I am struggling to ensure that the task actually runs every minute. I've tried a variety of approaches from using SystemClock.sleep() to the AlarmManager (both repeating alarm and a fixed alarm) but it seems that unless the device is charging any kind of repeating system has a variable repeat rate once the device is unplugged. Is there any way to run a stable consistently repeating service?
Have you implemented Timer? It works very well for what I use it for, but then again I haven't worried about the precision at all. For all I know it may be varying a bit but I doubt it. It seems pretty consistent to me.
Edit: I am not liable for your responsible or irresponsible use of this facility ;)
If you need to have a service that runs every minute, on the minute, you have two options:
Use AlarmManager.setRepeating(RTC_WAKEUP, ...). In this case, the phone will sleep, but the RTC inside the phone will wake it up every minute to handle the repeating event. This will work, but will not be terribly exact as a lot of things are happening after the phone wakes up so your code might not get execution time right away.
Obtain a WakeLock from PowerManager and use whatever you want to time your code (Timer, Handler, etc.). This forces the phone to never sleep, which means that it is most likely free to run your code almost exactly when you request.
Both approaches will definitely drain the battery of the phone fast. Normally, the phone can sleep for 4 or even 9 minutes between wakes, so waking up once per minute is a big change from that.