s60 s60 - 1 month ago 16
Android Question

AlarmManager setRepeating not working with daily interval

I encountered an issue while trying to setup a daily notification.

I used

AlarmManager
to setup an alarm at 6:00pm everyday

Intent myIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
if (calendar.get(Calendar.HOUR_OF_DAY) >= 18) {
calendar.add(Calendar.DATE, 1);
}

calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.HOUR_OF_DAY, 18);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 24*60*60*1000,
pendingIntent);


But I don't know why the first alarm is fired at exact 18:00, but the next alarm fires at random time. Sometime 19:30, sometime 20:06. I just don't understand what I'm wrong here.

I tried both
INTERVAL_DAY
or
24*60*60*1000
- nothing worked.
But it worked fine with interval of 1 minute, 5 minutes, 10 minutes, 1h etc.

AlarmReceiver:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service1 = new Intent(context, MyAlarmService.class);
context.startService(service1);
System.out.println("alarm");
}
}


MyAlarmService:

public class MyAlarmService extends Service {
private NotificationManager mManager;

@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}

@SuppressWarnings("static-access")
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);

mManager = (NotificationManager) this.getApplicationContext().getSystemService(this.getApplicationContext().NOTIFICATION_SERVICE);
Intent intent1 = new Intent(this.getApplicationContext(),MainActivity.class);

Notification notification = new Notification(R.drawable.ic_launcher,"Test notification", System.currentTimeMillis());

intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);

PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(this.getApplicationContext(), "Test", "Test a notification", pendingNotificationIntent);

mManager.notify(0, notification);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}

Answer

You have two problems:

  1. setRepeating() is inexact on Android 4.4+ with an android:targetSdkVersion of 19 or higher.

  2. You are not using WakefulBroadcastReceiver, my WakefulIntentService, or your own WakeLock, and so the device can fall back asleep between the time the alarm is triggered any by the time your service completes its work.

In this case, you can solve #2 easier by just moving the code from onStart() (which, BTW, has been deprecated for ~5 years) into onReceive() and getting rid of the service entirely. You only need a service here if you are doing disk I/O or network I/O; raising a Notification should be cheap.