Android Java - Alarm Manager Mostly Works Perfect But Sometimes Delayed - java

I am working on an alarm application. Users can set alarms in the application and some actions have to do when one of the alarms triggered. I used the first alarm manager set method. But only the first alarm worked right time. Others triggered after almost 5 minutes of delayed.
Intent intent = new Intent(applicationContext, OneShotAlarm.class);
PendingIntent sender = PendingIntent.getBroadcast(applicationContext, 0,
intent, FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) applicationContext.getSystemService(ALARM_SERVICE);
alarmManager.cancel(sender);
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmCalendar.getTimeInMillis(), sender);
Later, I found this. I changed set method to setexact method and all alarms looked like working perfectly.
alarmManager.setExact(AlarmManager.RTC_WAKEUP, alarmCalendar.getTimeInMillis(), sender);
But I saw sometimes still triggered with delay. Something like 5-8 minutes.
Where is my wrong?
UPDATE:
I kept log files when I first detect the error. I saw delay times in log files. Some of pre setexact method logs like below:
16:30:59 Next alarm set to 24/05/2020 16:35:00
16:35:00 Alarm triggered
16:35:00 Notification Sent
16:35:00 Next alarm set to 24/05/2020 16:40:00
16:44:47 Alarm triggered
16:44:47 Notification Sent
16:44:47 Next alarm set to 24/05/2020 16:50:00
16:54:48 Alarm triggered
16:54:48 Notification Sent
16:54:48 Next alarm set to 24/05/2020 18:00:00
And some of post setexact method logs like below:
03:00:00 Alarm triggered
03:00:00 Notification Sent
03:00:00 Next alarm set to 25/05/2020 07:00:00
07:08:14 Alarm triggered
07:08:15 Notification Sent
07:08:15 Next alarm set to 25/05/2020 08:30:00
08:34:47 Alarm triggered
08:34:47 Next alarm set to 25/05/2020 09:00:00
09:00:00 Alarm triggered
09:00:00 Next alarm set to 25/05/2020 18:00:00
UPDATE:
My alarm set code is inside of a method. I call it after every data update or triggered alarm. This way, I make sure always the next alarm can be set.

For current Android version, you should recall alarm manager again in onReceive. This is the example of Alarm Manager called every 5 second :
public class TestApplication extends Application {
private static Context context;
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
static void createAlarm() {
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, pendingIntent);
}
}
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm Manager Test", Toast.LENGTH_SHORT).show();
TestApplication.createAlarm();
}
}

Related

Resetting data everyday on android app as an asyn task

I have an app that needs to reset its text fields and other views everyday. Its like a daily tasks that remain constant but the progress has to be reset everyday or at 12am
That a really easy task to implement using AlarmManager.
Following this guide it should be easy for you.
Example:
//define your intent
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PedingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// Set the alarm to start at approximately 00:00 h(24h format).
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 00);
//repeteat alarm every 24hours
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
Now create a BroadcastReceiver called "AlarmReceiver" and inside it, do whatever you want to.
public class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//do whatever you want.
}
}
Maybe you should use a WakefulBroadcastReceiver depending of your task.

Doubts Regarding AlarmManager - Android

I have some doubts that I would like to clear regarding the AlarmManager class in Android.
I have an app that needs to:
Allow the user to set a time.
Start an alarm.
Then, even if the app is closed, it should start up on the preset time and do a certain function (like button.performClick()) in the main activity.
So, I have successfully created an activity called alarm.java, created the layout in res\layout and added it to AndroidManifest.xml. Also, I have successfully set the alarm as follows in my alarm.java class:
onCreate(){
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(context, MyActivity.class);
pi = PendingIntent.getBroadcast(this.getApplicationContext(), ALARM_ID, intent, 0);
}
onClick(){
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Toast.makeText(getApplicationContext(), "Alarm Set For " + hour + ":" + minute + " " + ampm, Toast.LENGTH_LONG).show();
}
Now, in my MyActivity.java class, which is the main activity, I have added the BroadcastReceiver
public BroadcastReceiver AlarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
/*This is the part I got from SO for starting an activity from `BroadcastReceiver`
Intent i = new Intent();
i.setClassName("com.kanishka.nightstalker.homeautomation", "com.kanishka.nightstalker.homeautomation.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);*/
Toast.makeText(getApplicationContext(), "APP STARTED", Toast.LENGTH_LONG).show();
button.performClick();
}
};
Obviously, this method isn't working as I see no Toast popping up after elapsed time. I kinda understand what the issue is, and I should be using a Service for this. But from what I know, AlarmManager itself runs in the background and SHOULD trigger the BroadcastReceiver of MyActivity.java on elapsed time. Where am I going wrong?
Where am I going wrong?
You are using setInexactRepeating(). Here, "inexact" means "not exact", and so the alarm will occur sometime within INTERVAL_DAY of your requested time.
You are taking the current time, then setting the hour and minute, which could result in a time in the past.
You are creating an Intent for MyActivity, which is probably not a BroadcastReceiver (or, if it is, MyActivity is a very odd name to choose).
If you want the alarm to go off "even if the app is closed", then you need to use a BroadcastReceiver that is registered in the manifest.
It is not possible to "do a certain function (like button.performClick()) in the main activity", as there will not be an activity "if the app is closed".

Alarm Manager does not execute broadcaster class

I'm trying out alarms and have hit a wall. I don't think my alarm is setting up properly because I never get a confirmation after the alarm is supposed to go off. Here's how I call on the alarm manager:
long alarmtime=new GregorianCalendar().getTimeInMillis()+10*1000;//run after 10 seconds
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmman = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmman.cancel(pi); // cancel any existing alarms
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
alarmtime, 10 * 1000, pi);//run every 10 seconds
And here's my AlarmReceiver.java:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "TEST", Toast.LENGTH_LONG).show();
}
}
However, the TEST text does not appear, and I can't figure out why.
Since you are using the AlarmManager.ELAPSED_REALTIME_WAKEUP argument, your initial alarm-time should be base on the elapsed real time of the device:
long alarmtime = SystemClock.elapsedRealtime() + 10 * 1000;
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmtime, 10 * 1000, pi);
(see this link).
For a BroadcastReceiver it's probably PendingIntent.getBroadcast() instead of PendingIntent.getService(). You are also cancelling the alarm, just update your PendingIntent like this and try not cancelling before:
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
Read the documentation thoroughly for further information.
Make sure that the BroadcastReceiver is being called by doing a System.out.println("TEST"); instead of Toast. If you are able to see that in your logcat, then the problem probably is that you need to run the Toast in UI thread.

Why AlarmManager fires are inconsistent

I am registering an Alarm manager in the onResume() state in my MainActivity.java (which is the main activity where the program start)
protected void onResume() {
super.onResume();
if (Helper.isNetworkAvailable(this)) {
Intent intent = new Intent(this, NewsIntentService.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),
10 * 60 * 1000, pi);
} else {
// nothing done
}
}
However I was getting inconsistent results, the following code runs good and with no errors, it shows that the PendingIntent should be fired at every 10 minutes but the results where on the following from logcat for example:
It starts working good:
2:00 pm (fired), 2:10 pm (fired), 2:30 pm (fired), ...
But after some time:
3:20 pm (fired), 3:27 pm (fired), 3:33 pm (fired), 3:38 pm (fired) ...
The question is at what life cycle of the activity it is best to register an AlarmManager and if what I did is correct what is the reason for the inconsistent run.
use the following code it worked for me:
1- private SharedPreferences prefs;
2-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Launch SharedPreferences
prefs = getSharedPreferences("Alarm", MODE_PRIVATE);
3-
protected void onResume() {
super.onResume();
if(!prefs.getBoolean(Helper.ALARM_SET, false)) {
Intent intent = new Intent(this, NewsIntentService.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),
10 * 60 * 1000, pi);
Log.i(Helper.ALARM_SET, "Alarm is set.");
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(Helper.ALARM_SET, true);
editor.commit();
}
}
Explanation:
The Use SharedPreferences to save a boolean value AlARM_SET, simple precise and this code will work even if the phone has restarted or turned off.
Your onResume is getting called at those times, hence triggering the alarm and once again setting it for next ten minutes.
If your end result is to invoke a functionality on Alarm, try to set the next alarm there, call your alarm once in onCreate of your MainActivity.(Check for the first run, use a File for the same or just Shared Preference) Let the rest be handled by the service/function/code which is run upon triggering the alarm.
Check here for complete implementation.
The flow would be something like:
MainActivity--> onCreate--> Check if first run--> Yes--> Register Alarm and execute immediately--> Invoke function/code-->Let this code set the next alarm.
The docs for AlarmManager clearly state that repeating alarms are inexact -- hence the drift you observe via Logcat.
Note: 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.
A block of the code that you can use:
public void schedule(final Context context) {
int alarmCode = YOUR_ALARM_CODE;
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, alarmCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
final Calendar calendar = yourCalendar();
final AlarmManager alarm = (AlarmManager) context.getSystemService(Activity.ALARM_SERVICE);
final long time = calendar.getTimeInMillis();
alarm.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}

preventing android daily alarm from running the intent during alarm setup

I followed the instructions in this thread to create a daily alarm that starts a service at 12:30 each day which shows a notification. The problem I'm having is that setting the alarm also triggers the service (=> and the notification) every time the app starts.
Since I figured that the alarm will run only at the specified time (12:30) then I have no problem setting it when the app starts.
I realize that setting the alarm from scratch every time the app is launched is a bit ineffective since it only needs to be set once (I made it set on device boot as well), but it seemed like the easiest way.
So what's the best way to fix this? is there a way to set the alarm for the specified time without running the intent when setting?
Here's the code if you are interested (this function is called every time when launching the app):
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.setTimeZone(TimeZone.getTimeZone("GMT"));
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
thanks in advance.
After trying several things, I used the information in this thread to preform a check if an alarm already exists, and setting one only if there isn't one already.
code:
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
boolean alarmUp = (PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_NO_CREATE) != null);
// check if an alarm already exists
if (alarmUp == false)
{
// set an alarm in case there isnt one already set
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
if (dailyCheckTime.getTimeInMillis() < Calendar.getInstance()
.getTimeInMillis()) {
dailyCheckTime.set(Calendar.DATE,
dailyCheckTime.get(Calendar.DATE) + 1);
}
AlarmManager alarm = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}

Categories