AlarmManager setExact with WakefulBroadcastReceiver sometimes not exact
This behaviour is added in API 19:
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 AlarmManager.
Important: setExact()
still does not have to be exact, as the docs state:
The alarm will be delivered as nearly as possible to the requested trigger time.
Android AlarmManager.setExact() not firing
There are some considerations depending in the Android version in which you are testing the alarm, but if you are testing for Android 6 or later then try the next code:
// Init the Alarm Manager.
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Setting the PendingIntent to be fired when alarm triggers.
Intent serviceIntent = new Intent(context.getApplicationContext(), YourService.class);
PendingIntent pendingServiceIntent = PendingIntent.getService(context, 0, serviceIntent, 0);
// Set the alarm for the next seconds.
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + seconds * 1000, pendingServiceIntent);
alarm manager can't start at exact time in android
after lots of researches, I finally found API 26 added a new method for pending intent called getForeGroundService()
so the code should look like this :
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener( view -> startBackup());
}
private void startBackup() {
Intent serviceIntent = new Intent(getApplicationContext(), ExampleService.class);
Calendar cal = initCalendar(10, 0, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= 26) {
PendingIntent pintent = PendingIntent.getForegroundService(getApplicationContext(), 6546548, serviceIntent, 0);
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
}else if (Build.VERSION.SDK_INT >= 23) {
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
} else if (Build.VERSION.SDK_INT >= 19) {
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
alarm.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
} else {
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
}
}
private Calendar initCalendar(int hour, int minute, int second) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
return calendar;
}
}
AlarmManager.setExact() does not work
The issue is you do not set the mainAlarm for tomorrow on your mainAlarmReciever
.
Imagine that your mainAlarmReciever->onRecieve
run at 11:54:59 P.M tonight. And it does whatever tasks you want to do. You should also set the mainAlarm for Tomorrow at 11:54:59 P.M in your onRecieve function.
Another option is using setRepeating (as CommonsWare mentioned it is not exact after API 19+).
AlarmManager setExact in Android 5.1
So what do I do if I need to set an alarm for an exact time, even during Doze, in Android 5.1?
Devices running 5.1 do not doze, so you need not worry about that. This
alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent)
will work as expected in 5.1. The newer setExactAndAllowWhileIdle was introduced for use on devices running 6.0+. Your code snippet is ok.
alarms in Android 5.1 (API level 22) or lower do not fire when the system is in Doze
This is a bit of a confusing statement. What they mean to say here is alarms set using the 5.1 or lower API's (like setExact) do not fire when a device is in doze.
Android: Alarm not being triggered through AlarmManager
This part of your code seems wrong:
notificationIntent.setAction("com.example.basicalarmsetter.MatchNotification");
You're using the class name here. You need to use the action of the broadcast receiver, the one you put in your intent filter, a.k.a:
notificationIntent.setAction("com.example.notificationtest.MatchNotification");
Another issue: You're creating two alarms, which is unnecessary, at here:
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
assert alarmManager != null;
alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
At this section, following lines are unnecessary:
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
assert alarmManager != null;
The value RTC_WAKEUP is supposed to be used with System.currentTimeMillis()
, not SystemClock.elapsedRealtime()
.
The final of your MainActivity.java would look like this:
package com.example.basicalarmsetter;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
public class MainActivity extends AppCompatActivity {
private int uniqueId = 0;
// Schedules a notification in the future given the delay
@RequiresApi(api = Build.VERSION_CODES.O)
private void scheduleNotification(int matchId, long delay) {
// Construct the PendingIntent which will trigger our alarm to go off
Intent notificationIntent = new Intent();
notificationIntent.setAction("com.example.notificationtest.MatchNotification");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), matchId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) ;
long futureInMillis = SystemClock.elapsedRealtime() + delay;
// Set off our PendingIntent
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
}
// Sets an Alarm at a future specified date
@RequiresApi(api = Build.VERSION_CODES.O)
private void setAlarm(long notificationDelay) {
try {
System.out.println("Setting alarm at " + notificationDelay + " seconds");
// Sets off a notification after 5 seconds
scheduleNotification(uniqueId, notificationDelay);
uniqueId++;
} catch (Exception ex) {
System.out.println("Cannot print alarm!");
System.out.println("Exception: " + ex.toString());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAlarm(15000);
}
}
Related Topics
Creating Animation on Imageview While Changing Image Resource
Sending Message to a Handler on a Dead Thread When Getting a Location from an Intentservice
Google Map for Android My Location Custom Button
Android Viewpager Padding/Margin Between Page Fragments
Android Studio Could Not Find Any Version That Matches Com.Android.Support:Appcompat-V7:+
Service Intent Must Be Explicit: Intent
How to Call a Wcf Service Using Ksoap2 on Android
How to Resolve Target 'Android-16'
Disable Icon Colorstatelist in Navigationview
How to Remove White Underline in a Searchview Widget in Toolbar Android
Changing Values from Cursor Using Simplecursoradapter
How to Repeat Notification Daily on Specific Time in Android Through Background Service
Android: How to Check How Much Memory Is Remaining
Items Inside Gridview Getting Repeated When Screen Scrolls
Converting from Glsurfaceview to Textureview (Via Gltextureview)