I want to start a service every a predefined time.
From my main activity I call SetAlarm method of a WakefulBroadcastReceiver with this code:
public class MyReceiver extends WakefulBroadcastReceiver {
public static final String PREFS = "Prefs";
SharedPreferences mSettings;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Receiver", "START");
Intent service = new Intent(context, Awservice.class);
startWakefulService(context, service);
}
public void SetAlarm(Context context) {
String Hour = getDuration(context, "PREFS_HOURS","0");
String Min = getDuration(context, "PREFS_MINUTES","0");
Long LHour = Long.parseLong(Hour);
Long LMinutes = Long.parseLong(Min);
Long time = (LHour*60+LMinutes)*60*1000;
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+time, time , pi);
}
public void CancelAlarm(Context context) {
Intent intent = new Intent(context, MyReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
String getDuration(Context context, String value, String defaultValue) {
SharedPreferences mSettings = context.getSharedPreferences(PREFS, Activity.MODE_PRIVATE);
return mSettings.getString(value, defaultValue).toString();
}
The problem is that my code works but is inaccurate.
e.g. If I set the activation time every 2 minutes the broadcast receiver doesn't work every 2 minutes but as follows:
21:32:52.068
21:33:27.842
21:36:38.258
21:37:59.437
21:39:42.178
21:41:30.643
21:43:27.898
21:45:42.199
What is wrong? Thanks in advance!
On projects that have android:targetSdkVersion set to 19 the setRepeating() will not be exact. From the docs:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use. There
are new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent). Applications whose
targetSdkVersion is earlier than API 19 will continue to see the
previous behavior in which all alarms are delivered exactly when
requested.
From CommonsWare's Busy Coders guide:
The only way to get exact repeating would be to use setExact() and to
re-schedule the event yourself, rather than relying upon Android doing
that for you automatically. Ideally, you use setInexactRepeating(), to
help extend battery life.
Related
I'd like to repeat an alarm every 20 minutes.
So I tried:
manifest:
<receiver android:name=".AlarmReceiver" />
AlarmReceiver.class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intent2 = new Intent(context, MainActivity.class);
showNotification(context, "text", "text", intent2);
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
}
#TargetApi(Build.VERSION_CODES.N)
public void showNotification(Context context, String title, String body, Intent intent) {
...
}
}
and in my main activity:
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, 1200);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent);
It is working only the first time. I'd like to keep it repeating even when the app is not opening, any ideas?
Starting with KitKat (API 19), alarms are all inexact, meaning the system will batch alarms around similar times together. If you need exact timing, there are different APIs to call. Further complicating things, starting with Marshmallow, Android introduced the concept of Doze, which further restricts the when/how things can wake up the device. You can still use exact alarms, but need to use the API which allows it during idle (Doze) time: setAndAllowWhileIdle(). Bear in mind that when your alarm fires, you could be in a Doze window and your app will be restricted on what kinds of operations it can perform.
Try below for Repeating alarm on every 20 minutes interval
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),1000 * 60 * 20, pendingIntent);
Try to use android worker manager since it is working with doze mode as well. https://developer.android.com/reference/androidx/work/PeriodicWorkRequest#min_periodic_interval_millis
https://developer.android.com/reference/androidx/work/PeriodicWorkRequest
I am trying to create app where i need to send location updates every 1,5,10 minutes and so on.
When app is running, it work accurately but when it goes into background/sleep mode it doesn't work accurately.
I tried both the methods setRepeating/setInExactRepeating but none of them work in background mode.
public static void startSensorAlaram(Context ctx, long minutes) {
AlarmManager alarmManager = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
// Alarm_Receiver is a broadcast receiver.
Intent intent = new Intent(ctx, Alaram_Receiver.class);
intent.setAction(Utility.SENSOR_ACTION);
PendingIntent pi = PendingIntent.getBroadcast(ctx, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),minutes,pi);
// alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), minutes, pi);
}
public static void stopAlaramSensor(Context ctx) {
Intent intent = new Intent(ctx, Alaram_Receiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 1,
intent, 0);
AlarmManager alarmManager = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
Alarm Receiver - Broadcast receiver
public class Alaram_Receiver extends WakefulBroadcastReceiver {
private SharedPreferences sp;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
sp = context.getSharedPreferences(Utility.SHARED_PREFS, 0);
if (intent.getAction().equalsIgnoreCase(Utility.SENSOR_ACTION)) {
if (sp.getBoolean("logged_in", false)) {
// context.startService(new Intent(context,SensorService.class));
startWakefulService(context,new Intent(context,SensorService.class));
} else
Utility.stopAlaramSensor(context);
}
}
}
Note:- Min API version is 15 and compile version is 23.
There are two issues.
1) As of Android API >= 19, you should use new AlarmManager.setExact() method instead of set() or setRepeating(). Here is the quote from official document.
Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will
shift alarms in order to minimize wakeups and battery use. There are
new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent).
2) As of Android 6.0, there is a deep sleep mode introduced, called Doze.
It is designed to reduce battery consumption when device is being standby. There are so many restriction and what you could do in that mode is very limited. You need to use the new AlarmManager.setExactAndAllowWhileIdle() to make Alarm fired in Doze mode at your preferred time.
More information about Doze mode is available here Optimizing for Doze and App Standby
I use AlarmManager to set two action on time,
First action set on 10:00:00, and second action set on 10:15:00.
I can get two action broadcast,
and get first action broadcast on 10:00:03 (is OK),
but get second action broadcast on 10:29:15,14 minutes late!
How let AlarmManager can send broadcast on time ??
Set AlarmManager code:
#Override
public void onCreate() {
setSchedule();
}
private void setSchedule(){
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar offCal = Calendar.getInstance();
offCal.set(Calendar.HOUR_OF_DAY, 10);
offCal.set(Calendar.MINUTE, 15);
offCal.set(Calendar.SECOND, 00);
Intent offIntent = new Intent(this, AlarmReceiver.class);
offIntent.setAction(AlarmReceiver.ALUM_SCREEN_OFF);
PendingIntent offPending = PendingIntent.getBroadcast(this, 1,
offIntent, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC, offCal.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, offPending);
Intent onIntent = new Intent(this, AlarmReceiver.class);
onIntent.setAction(AlarmReceiver.ALUM_SCREEN_ON);
Calendar onCal = Calendar.getInstance();
onCal.set(Calendar.HOUR_OF_DAY, 10);
onCal.set(Calendar.MINUTE, 00);
onCal.set(Calendar.SECOND, 00);
PendingIntent onPending = PendingIntent.getBroadcast(this, 2,
onIntent, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, onCal.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, onPending);
}
Receiver code:
public class AlarmReceiver extends BroadcastReceiver {
public static final String ALUM_SCREEN_ON = "screenOn";
public static final String ALUM_SCREEN_OFF = "screenOff";
private static final String TAG = "AlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d(TAG, "get braodcast action:"+intent.getAction());
}
Hi you are using setRepeating method which wont give alarm at exact time.Alarm manager will strongly discourage other apps apart from system apps to trigger alarm accurately for the better battery optimization.so if u want to trigger alarm at a particular time means you can use setExact() method This also wont give you complete gaurantee but it will give you the most accuracy one .While setting multiple alarms at a single time make sure you are giving different ids in `
PendingIntent onPending = PendingIntent.getBroadcast(this, 2,
onIntent, PendingIntent.FLAG_UPDATE_CURRENT);
here you gave 2 as id and it should be different for different alarms.
Since KitKat the set and setRepeating APIs are not exact. If you absolutely need the alarm to run at a specific time, use setExact. Consider using setWindow instead if the alarm time is not critical.
There is no setExactRepeating, so if you need that, you need to use setExact and them re-arm your alarm. But unless your are doing time critical stuff, that's not recommended.
I have an alarm that I am wanting to repeat around every 5 minutes. For testing purposes, I have it set to repeat once every 5 seconds instead, as such:
AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
Intent intent = new Intent(getActivity(), CoordinateAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getService(getActivity(), 1, intent, 0);
int repeatSeconds = 5;
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
repeatSeconds * 1000, pendingIntent);
And the receiving IntentService prints a log statement when it receives the alarm. However, it fires around once every minute and a half instead of once every 5 seconds, where is it set incorrectly? I have also tried using setRepeating() instead of setInexactRepeating() but I get the same results.
Here is my alarm receiver:
public class CoordinateAlarmReceiver extends IntentService {
public CoordinateAlarmReceiver(){
super("CoordinateAlarmReceiver");
}
/*
Alarm received, get new contacts which then shows notification
*/
#Override
protected void onHandleIntent(Intent intent) {
MyLog.i("coordinate alarm received");
//new GetNewContactsTask(this).execute();
}
}
I assume you are on api 19 or above. The alarmmanager documentations says:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
You tried using setRepeating() but on api 19 and above this calls setInexactRepeating(). On 19 and above you
setInexactRepeating(): Schedule a repeating alarm that has inexact trigger time requirements; for example, an alarm that repeats every hour, but not necessarily at the top of every hour.
This explains your weird result.
If you want to set is at a excat time, you should use setExact. Unfortunalety there is no setExactRepating so you have to create this yourself. Schedule a new alarm after one executes or something like that.
Note in the alarmmanager documentation:
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Maybe you should take a look at this.
I had a similar problem in which I needed a Service fired every 15 seconds... I did the following.
I have a class that extends Application called MyApplication. This class holds an instance of an alarm manager.
public class MyApplication extends Application {
private MyAlarmManager alarmMgr;
#Override
public void onCreate() {
Log.d(TAG, "MyApplication onCreate");
super.onCreate();
Log.d(TAG, "initing alarmMgr ...");
alarmMgr = new MyAlarmManager(this);
}
public MyAlarmManager getAlarmManager(){
return alarmMgr;
}
}
An AlarmManager called MyAlarmManager creates, starts & stops the alarms AND NOW sets the next alarm for this one service.
public class MyAlarmManager {
private MyApplication mApp;
private Intent intent;
private PendingIntent pendingIntent;
private AlarmManager alarmMgr;
private static final long FREQUENCY = 15000;
public MyAlarmManager(Context context) {
mApp = (MyApplication) context;
// Android alarm service
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// service to be fired every 15 seconds
intent = new Intent(context, MyService.class);
pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
setNextAlarm();
}
public void setNextAlarm(){
Log.d(TAG, "setting next alarm...");
alarmMgr.set(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + FREQUENCY), pendingIntent);
}
private void stopAlarms(){
Log.d(TAG, "stopping Alarms");
alarmMgr.cancel(pendingIntent);
}
}
When the Service is fired I get an instance of MyApplication, get the AlarmManager and schedule the next alarm.
public class MyService extends Service {
MyApplication mApp;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "in onStartCommand");
// init the app reference if needed
if (mApp == null) {
Log.d(TAG, "app was null. Creating now...");
mApp = (MyApplication) getApplicationContext();
}
// schedule the next zone check
mApp.getAlarmMgr().setNextAlarm();
// custom functionality ...
}
I am trying to use AlarmManager to accomplish a recurring task. I am using setInexactRepeating() and have set the interval to every 15 minutes (just for testing purposes) however, it doesn't seem to be working. Any ideas?
Here's my code:
AlarmReceiver
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.w("CacheCrusader", "Recurring Job: Clearing Cache");
}
}
Setter
private void setRecurringAlarm(Context context) {
Calendar updateTime = Calendar.getInstance();
updateTime.set(Calendar.HOUR_OF_DAY, 20);
updateTime.set(Calendar.MINUTE, 15);
Intent downloader = new Intent(context, AlarmReceiver.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context,
0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getSystemService(
Context.ALARM_SERVICE);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP,
updateTime.getTimeInMillis(),
AlarmManager.INTERVAL_FIFTEEN_MINUTES, recurringDownload);
}
Code that Sets the Setter
Context context = getApplicationContext();
setRecurringAlarm(context);
Android Manifest Declaration
<receiver android:name=".receiver.AlarmReceiver"></receiver>
No errors are generated in the logcat... the alarm just never fires.
Well, it's inexact so... If you set it the interval to 15 mins, you have to wait for at least half an hour to be sure it has/has not fired. After the starting time you have set (20:15). Try it out with something like 1 min interval for testing. And, if you need a more reliable schedule, use setRepeating(), or possibly set() where each alarm invocation registers the next one.