I would like to register a BroadcastReceiver in the Android manifest, or in code if necessary, that would send a broadcast to my application based on time.
e.g. i would like my onReceive to be called time-dependently by the Android OS
at say a regular interval
or at a given time of day
or once after a specific amount of time has lapsed (say after 44 minutes from some call in my application)
How might that be possible without leaving my app running in the background all the time ?
See AlarmManager and android.intent.action.TIME_TICK
Related
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.
I need to create an android service that:
Starts whenever the screen is on (whether it is at boot time or not)
sends a notification every 20 minutes (if the screen is on)
stops whenever the screen is off
Every tutorial I've read uses an activity, but I need this to be a service because the app is not supossed to be running other than when the user wants to change a setting. The documentation says I need an IntentService, but I cannot stop that manually and I cannot use a Service because it is a long running operation. I tried with an alarm manager but it didn't worked, I don't even bother to show you the code because I really don't understand it. I do not know how to make the service check if the screen is on or not, if I use a BroadcastReceiver it won't be inmediately processed so I am just stuck
To implement your requirement. You need 3 things such as Service, BroadcastReceiver & AlarmManager :
AlarmManager [which will fire after every 20 minutes]
Service [which will make changes like showing notification as system gets notifies after every 20 minutes for your particular msg]
BroadcastReceiver [which will check for screen on/off right from booting to shutting down]
Refer these links :
http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
http://androidexample.com/Screen_Wake_Sleep_Event_Listner_Service_-_Android_Example/index.php?view=article_discription&aid=91&aaid=115
I am using AlarmManager to poll user location periodically which is working fine- Now I would like to give my app users an option so they can restrict the location polling by specifying hours say 'Between 8PM to 10PM'.
Right now I am using AlarmManager.setRepeating method for scheduling but I am unable to configure my alarm service so that it runs every day but within certain hours.
I already know how to schedule a recurring task using AlarmManager at particular time of day but how to set the end time is what I am looking for.
You can't tell AlarmManager to do exactly that, but you could check whenever your service gets called to see if it's within the specified hours. If it is, then you proceed as normal, if not then you reschedule the alarm to start at the beginning of the next polling period.
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".
i want my app to run in the background as it has to get the time every second..and do some task when the user sets a time and wants the app to do some task at that time..!!
Have you considered using the AlarmManager?
Android provides an AlarmManager
service that will let you specify an
Intent to send at a designated time.
This intent is typically used to start
an application at a preset time.
(Note: If you want to send a
notification to a sleeping or running
application, use Handler instead.)
If you do something every second, it us unlikely the user's device will reach the 24 part without being plugged in to power.
Android apparently already contains a scheduling service so you don't need to create your own.
Does this article help. Don't forget to follow up the links provided in that article.
I agree with every single person in this thread! AlarmManagers are your best friends when it comes to executing services at a certain interval. They are very easy to set up too, here's a very simple example of a repeating alarm:
//Get the alarm service
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
//Create the intents to launch the service again
Intent new_intent = new Intent(<The intent to set off>);
PendingIntent p_intent = PendingIntent.getBroadcast(this, 0, new_intent, 0);
//Create a repeating alarm
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, <Time in milliseconds to set off first alarm>, <How long between each alarm in milliseconds>, p_intent);
Note that I'm using an inexact alarm to set of the alarm so it doesn't try to interrupt any other important services. It is possible to use an exact alarm but if your execution isn't really that important I highly suggest inexact alarms. You can find a lot more info below:
http://developer.android.com/reference/android/app/AlarmManager.html