AlarmManager on API19 has the method setExact() to set an exact alarm.
Exact means --> If I set an alarm to 2:01 pm it will be triggered at 2:01 pm
On API 23 - Marhsmwallow (6.0) there is a new method setExactAndAllowWhileIdle(), but as of the reference it is not EXACT because it will trigger only every minute and in low power idle mode only every 15 minutes.
Exact != every 15 minutes :-)
So how can I achieve an exact alarm with AlarmManager in 6.0?
If a user adds a reminder or a calendar appointment and wants to be informed 10 minutes before the event it should show the alarm EXACT 10 minutes before the event. With setExactAndAllowWhileIdle() this seems is not possible.
Reference Link:
http://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
So how can I achieve an exact alarm with AlarmManager in 6.0?
You are welcome to try setAlarmClock(), as AFAIK it is unaffected by Doze mode. Otherwise, AlarmManager is not a viable option for you. Even having your app on the battery optimization whitelist will not help, as AlarmManager behavior does not change based on the whitelist.
You are welcome to use GCM, as a high-priority message should give you an opportunity to alert the user. This, of course, requires network connectivity.
The only offline solution that I am aware of — and that I am presently testing — is to have the user add your app to the battery optimization whitelist, then use a foreground service (to try to keep your process around), a ScheduledExecutorService (for the timing), and a partial WakeLock (to keep the CPU on). This will be fairly devastating to the user's battery.
Using setExactAndAllowWhileIdle() for a one-time alarm will fire exactly on the given time even in Doze idle mode. So this probably is the way to go.
Problems start, if you want to repeat the alarm at a rate of < 15 min (or set any other at a time < 15 min away from the last one), as this will not work in Doze idle mode, where such alarms are forced to the next 15 min or are executed when idle maintenance starts, which happens for about ten minutes first after 1 hour, then after another 2 hours, then after another 4 hours and so on.
- EDIT -
As of today Nov 17, Dianne Hackborn writes in this Post's comments:
"For what it's worth, the minimum time between while idle alarms will be changing to 9 minutes at some point relatively soon (even on devices running the current Marshmallow builds)."
This doesn't change anything fundamentally though.
Here are my discussion with Ian Lake on Google+!
setExactAndAllowWhileIdle() is exact and should work.
The 15 minutes time frame is wrong in the java doc.
I was trying to create an automation system running in the background. My frequency range was between 1-15 minutes. My wish was not to use a foreground service. By looking at the name of the method "setExactAndAllowWhileIdle", I thought that yeah it is safe to go with one-time alarms, scheduling the next one when done.
However, I couldn't find a way to run code in doze mode with alarms running more frequent than 15 minutes. Instead, I choose to start a foreground service when doze mode gets activated and stop that foreground service when phone awakes. User won't be seeing your foreground notification while using his/her phone. I don't care much about the ones in doze mode.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
if (pm.isDeviceIdleMode()) {
//startAutomationForegroundService();
} else {
//stopAutomationForegroundService();
return;
}
AutomationReceiver.completeWakefulIntent(intent);
return;
}
}
You need to register "android.os.action.DEVICE_IDLE_MODE_CHANGED" intent filter into your WakefulBroadcastReceiver. Care putting it into manifest may not help.
Related
I am writing a reminder app for Android that repeatedly sends the user a notification with increasing intervals in between. Namely after 30s, 2m, 10m, ..., 25 days, 4 months, 2 years.
I originally intended to do this by registering a JobService that would run every 30s to check whether it was time to send a notification. However, as this post warns (and as I found out):
Which means that my job runs at most once every 15 minutes, and prevents me from sending my 30s, 2m and 10m reminders.
What would be the correct/most efficient way of implementing such functionality?
(Also, running a job every 30s to check for the 2y notification is quite inefficient)
Don't make it a periodic job. Make each next schedule a one-time event. Each time the job is triggered schedule a new item.
I have an Android Application that uses a Countdown Timer that lasts for around 2 days. What is the best method to avoid my Countdown Timer from being killed by the Android Application Manager even if the user enables a power saving mode or restarts their phone ? (Sorry if this is a senseless question to answer, for the reason that I am new to Android development.)
What is the best method to avoid my Countdown Timer from being killed by the Android Application Manager even if the user enables a power saving mode or restarts their phone ?
That is not possible. Moreover, it is very wasteful (tying up system RAM, spending CPU time). If you want to get control at a certain time in the future, use methods on AlarmManager (e.g., setAlarmClock()). If you want to find out how much time remains between now and that certain time in the future, find out the current time (e.g., System.currentTimeMillis()) and subtract that from the future time to calculate the difference in times. To handle a reboot, you would need to set up the AlarmManager again, by using a BroadcastReceiver set up to respond to ACTION_BOOT_COMPLETED.
Ever played Candy Crush? Know how you run out of lives and have to wait 30 minutes to regenerate a new life and up to a maximum of 5? That is idea I am trying to implement in my app but I am uncertain on how to have code running even when the user closes app and/or phone.
My question is how to have a timer constantly running in the background of phone until the timer hits X minutes. Would I use the Timer class for this? Because I am familiar with that class and already have a form of it implemented in my app.
There are two pieces to your question:
To actually have a timer running so that you have an action taken after a certain period of time, use the AlarmManager. This should only be used if you are going to proactively interrupt or notify the user.
Your scenario doesn't actually need a timer, and it's more efficient not to use one unnecessarily. Instead, store a timestamp. When your app is opened again, compare the current time to the timestamp and calculate the effect. In the regenerating-lives example, you'd compare timestamps, see that 100 minutes have passed, divide by 30 minutes, and add 3 lives (maybe keeping the extra 10 minute remainder).
If you want timer to run in background you may use AlarmManager. You can set Alarm at specified intervals or you can set it in service if you want single shot alarms. Also while using AlarmManager beware that if your phone goes down then all alarms you've set will be vanished. So take care that you are saving alarm times before phone goes off. Take a look at:
http://developer.android.com/reference/android/app/AlarmManager.html
While using AlarmManager, use correct PendingIntent flags or you could lose previous alarms. If you still want more information you can raise here or have a google.
I don't think you can keep a timer running for you application even when the application is closed. Here is an idea i think about:
You need to start a timer when the life is gone and your application is running.
On your application close event, save that timer value in a persistent storage such as file
On appliction start, read the timer value from the persistent storage, and restart the timer for the remaining time
Once timer expires, generate a new life.
Hope it helps!
I found this answer that might be of great help. Hope it helps others.
There are several different approaches.
You can make use of the System's AlarmManager.
You can make your own Service.
You can make your TimerObject persist.
Check the link for the complete answer and links.
I've got a clock in my widget that I'm making and I want it to update every minute in sync with the system clock. ACTION_TIME_TICK seems like the perfect solution however much of my research says it's impossible in an AppWidget while others say there are workarounds but their very vague.
I'd prefer not to do an AlarmManager as I'd have to update very frequently to make sure that it changes minutes when the system clock changes minutes and that would drain the battery more.
Is there a workaround for ACTION_TIME_TICK or what's the best way to update every minute in sync with the system clock with minimal battery drain?
Is there a workaround for ACTION_TIME_TICK
ACTION_TIME_TICK can only be registered via registerReceiver() from something that is already running. In your case, that "something" would need to be a constantly-running Service, and that's generally an anti-pattern. Users and the OS can get rid of that service when desired.
I would find a way to lightly relax the "in sync with the system clock" requirement, then use AlarmManager. After all, Android is not a RTOS, so nothing will be "in sync with the system clock" in any guaranteed sense.
Using AlarmManager, you would specify the first alarm to be the "top" of the next minute, with a period of 60 seconds and setRepeating(). Or, you would set(), scheduled for the "top" of the next minute, then schedule the next one via set() as part of your own processing, if you think you can manually correct for drift better that way.
if you just need to display it when your app runs then just update it using asyncTask
but if you need it's value even in the background then using service would be the best idea
I'm using for my Android Service an Handler that reapeat some operation each 60 minutes (1 hour), with a PartialWakeLock to keep the phone not sleeping. But this cause a lot of battery usage.
So a decided to study about AlarmManager (i'm noob) that someone wrote here to be perfect for this kind of things..
But now reading along the web i find that who uses AlarmManager, still need a WakeLock. Is it true?
What is the best way to run a cycle each 60 minutes (1 hour), without kill the battery?
Thanx
P.S.
AlarmManager Android Developer
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes. If your alarm receiver called
Context.startService(), it is possible that the phone will sleep
before the requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a separate wake
lock policy to ensure that the phone continues running until the
service becomes available.
But so seems that i need 2 wakelock vs just 1 wakelock using handler....is it true?
I have made many test and this is the result:
-Alarm Manager save more battery than using handler+wakelock for long timing operation.
But you must use an additional wake lock to your activity/service started by the alarm, because the alarm manager wake lock doesn't cover it.
Even of this method uses two WakeLock the battery seems to be more efficient and with more life! During the tests (2days) the AlarmManager use 6 time less battery than other method. In my own case...
Hope this can help some one!
I suggest you to use AlarmManager to handle events with 1 hour interval.
Because we don't know exactly what you what to achieve we can't provide a more in deep answer/suggestion sorry.
I am not sure if it is still relevant,
but the answer is: using AlarmManager is preferred. You only need a WakeLock to keep phone running after AlarmManager has woken it up to send an Intent to your receiver and until service has finished its work. So phone will be awake only for a couple of milliseconds, compared to "all the time".