Reputation: 1862
I am using alarm manager to fire broadcast at specific time. But after testing it so many times, I found sometimes broadcast is received late. Sometimes 5 seconds, 10, 15 or even more sometimes. Specially when device is locked. I have done various experiments. My least problematic code is here.
Even after using wake lock, I don't know what I am lacking.
Firing Intent
Intent intent = new Intent(this.getApplicationContext(), BroadCastReceiver.class);
//..... some extras
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), code, intent, 0);
manager.setRepeating(AlarmManager.RTC_WAKEUP, time, 1000 * 120 , pi);
Receiving broadcast
public void onReceive(Context context, Intent intent)
{
WakeLocker.acquire(context);
.......
Intent alarm = new Intent(context, xyz.class);
alarm.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarm);
}
and releasing Wakelock in destroy() of xyz activity.
Custom WakeLocker class public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context ctx) {
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "haris");
wakeLock.acquire();
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
Upvotes: 3
Views: 691
Reputation: 918
According with official documentation:
AlarmManager.setRepeating(...)
as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
It means you must set your PendingIntent again when you receive it.
Something like this:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
switch (intent.getAction()) {
case AlarmHelper.ACTION_MY_ALARM:
doWhatYouNeed();
long nextTime = getNextAlarmTime();
AlarmHelper.resetAlarm(nextTime);
break;
...
}
}
}
To get next alarm time you can use System.currentTimeMillis() + interval or pass it to intents extras, the second way is more accurate. And, I'm sure, you don't need WakeLock in BroadcastReceiver.
public class AlarmHelper {
public static void resetAlarm(long time) {
Intent intent = createIntent();
PendingIntent pendingIntent = createPendingIntent(intent);
setAlarmManager(time, pendingIntent);
}
public static void setAlarmManager(long time, PendingIntent pendingIntent) {
AlarmManager alarmManager = (AlarmManager) MyApp.getAppContext().getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
}
}
Upvotes: 1