I am working on a Reminder that sends notification on fixed time to the user.
The alarm is getting off instantly ...
I tried most of the suggestions over s
The main problem appears to be with this line:
calAlarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j]));
What you need to realise is this is just setting the Day of the week which will be displayed in output - It is not changing the underlying date to match, which I think is what you are expecting.
Try using the following code to alter your dates to set an alarm for each day selected:
String strSpit[] = time.split(":");
String strDays[] = reminderList.get(i).getDays().split(","); //"days": "1,2,3,4,5,6,7"
Calendar todayWithTime = Calendar.getInstance(); //setting current time is redundant
todayWithTime.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0]));
todayWithTime.set(Calendar.MINUTE, Integer.parseInt(strSpit[1]));
Calendar alarm;
int today = todayWithTime.get(Calendar.DAY_OF_WEEK);
int offset, target;
for (int j = 0; j < strDays.length; j++) {
alarm = (Calendar) todayWithTime.clone(); //now you have todays date, but correct time
target = strDays[j];
//saturday is biggest day of week
offset = (Calendar.SATURDAY - today + target) % 7; //work out how many days in the future the next occurance of this day is
alarm.add(Calendar.DATE, offset);
... // the rest stays the same
}
Got hit by same issue and stumbled upon this question while finding the solution. When setting the alarm, You just need to place a check that your alarm date should not be before current date.
public static void setReminder(Context context,Class<?> cls,long milliseconds, int event_id,String eventName)
{
Calendar calendar = Calendar.getInstance();
Calendar notificationcalendar = Calendar.getInstance();
notificationcalendar.setTimeInMillis(milliseconds);
if(!notificationcalendar.before(calendar)) { // **just add this check**
ComponentName receiver = new ComponentName(context, cls);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
Intent intent1 = new Intent(context, cls);
intent1.putExtra("eventName", eventName);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, event_id, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, notificationcalendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
Finally I found a way to do that by storing PendingIntent requestCode
in database (used ROOM) , then cancelling all the alarm by retrieving all the requestCode
from DB
AlarmIdPojo
@Entity
public class AlarmIdPojo {
@PrimaryKey(autoGenerate = true)
public int id;
private int requestCode;
public AlarmIdPojo() {
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
}
AlarmIdDAO
@Dao
public interface AlarmIdDAO {
@Query("select * from AlarmIdPojo")
List<AlarmIdPojo> getAllRequestCode();
@Query("delete from AlarmIdPojo")
public void deleteAllRequestCode();
@Insert(onConflict = REPLACE)
void addRequestCode(AlarmIdPojo pojo);
}
AppDatabase
@Database(entities = {AlarmIdPojo.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract AlarmIdDAO requestIdPojo();
@Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
return null;
}
@Override
protected InvalidationTracker createInvalidationTracker() {
return null;
}
}
callReminder
private void callReminder() {
// java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
// because of this Exception , we are doing this in AsyncTask
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
List<AlarmIdPojo> idList = appDatabase.requestIdPojo().getAllRequestCode();
Intent notifyIntent = new Intent(MainActivity.this, MyReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent;
for (int i = 0; i < idList.size(); i++) {
int requestId = idList.get(i).getRequestCode();
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, requestId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Cancel alarms
try {
alarmManager.cancel(pendingIntent);
} catch (Exception e) {
Log.e(TAG, "AlarmManager update was not canceled. " + e.toString());
}
}
appDatabase.requestIdPojo().deleteAllRequestCode();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// Once every request code is deleted , then once again call setReminderNotification() for fresh data.
setReminderNotification();
}
}.execute();
}
setReminderNotification
private void setReminderNotification() {
Intent notifyIntent = new Intent(this, MyReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent;
// Taking existing offline reminder data from sharePreference
Type type = new TypeToken<List<UserReminderPojo>>() {
}.getType();
List<UserReminderPojo> reminderList = new Gson().fromJson(sharedPrefUtils.getString(sharedPrefUtils.DEFAULT_REMINDERS), type);
for (int i = 0; i < reminderList.size(); i++) {
String time = reminderList.get(i).getTime();
String strSpit[] = time.split(":");
String strDays[] = reminderList.get(i).getDays().split(",");
Calendar todayWithTime = Calendar.getInstance();
todayWithTime.set(Calendar.SECOND, 0);
todayWithTime.set(Calendar.MILLISECOND, 0);
for (int j = 0; j < strDays.length; j++) {
Calendar alarm = Calendar.getInstance();
alarm.set(Calendar.SECOND, 0);
alarm.set(Calendar.MILLISECOND, 0);
alarm.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0]));
alarm.set(Calendar.MINUTE, Integer.parseInt(strSpit[1]));
alarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j]));
int randomPendingIntentId = generateRandomId();
notifyIntent.putExtra(Constants.REMINDER_NAME, reminderList.get(i).getName());
notifyIntent.putExtra(Constants.ID, randomPendingIntentId); // passing it , so that we can cancel this PendingIntent with this Id, once notification is shown.This is done to prevent past time alarm firing
notifyIntent.putExtra(Constants.REMINDER_DAY, viewFunctions.getDayInt(strDays[j]));
pendingIntent = PendingIntent.getBroadcast(this, randomPendingIntentId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (alarm.before(todayWithTime)) {
alarm.add(Calendar.DATE, 7);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, alarm.getTimeInMillis(), pendingIntent);
insertToDB(randomPendingIntentId);
}
}
}
insertToDB
// Saving to DB. keeping track of PendingIntent unique id.
private void insertToDB(int randomPendingIntentId) {
alarmIdPojo = new AlarmIdPojo();
alarmIdPojo.setRequestCode(randomPendingIntentId);
// java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
// because of this Exception , we are doing this in AsyncTask
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
appDatabase.requestIdPojo().addRequestCode(alarmIdPojo);
return null;
}
}.execute();
}
I have the same issue before, please check the following details:
Not working code sample:
Intent notificationIntent = new Intent("~~~.BaseActivity");
notificationIntent.putExtra("type", 2);
notificationIntent.putExtra("appName", "testApp");
notificationIntent.putExtra("messageEN", "Good evening");
notificationIntent.putExtra("notificaitonID", 4);
PendingIntent broadcast = PendingIntent.getBroadcast(context, 4,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 18);
calendar.set(Calendar.MINUTE, 10);
calendar.set(Calendar.SECOND, 0);
// this is to show it at the 6:10
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
broadcast);
Working Code:
Intent notificationIntent = new Intent("~~~.BaseActivity");
notificationIntent.putExtra("type", 2);
notificationIntent.putExtra("appName", "testApp");
notificationIntent.putExtra("messageEN", "Good evening");
notificationIntent.putExtra("notificaitonID", 4);
PendingIntent broadcast = PendingIntent.getBroadcast(context, 4,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 18);
calendar.set(Calendar.MINUTE, 10);
calendar.set(Calendar.SECOND, 0);
// this is to show it at the 6:10
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar nowCalendar = Calendar.getInstance();
if (calendar.after(nowCalendar)) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
broadcast);
} else {
calendar.add(Calendar.DAY_OF_MONTH, 1);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
broadcast);
}
it's done only when you about to set the repeating, you need to check if it's passed or not, and if it's passed just add the wanted time for repeating
You alarm is going off instantly because Android will fire off any alarms that are scheduled in the past.
Some of your alarms are getting scheduled in the past because the following code is not working as you expect. Sample code from your question:
if (calAlarm.before(calNow))
{
//if [it's] in the past increment
calAlarm.add(Calendar.DATE, 1);
}
In the above code you are only adding one day to your alarm if the alarm is in the past. So let's say you are running this code on Friday and you read an alarm for Monday. Your code will add one day to the date making it Tuesday, schedule that alarm. The alarm is in the past because Tuesday is still before Friday, so Android will fire off that alarm shortly after being scheduled.
It is unclear from your question what you wish to do with the reminders that are in the past. One possible solution is to schedule them 1 week into the future.
if(calAlarm.before(calNow))
{
// If it's in the past increment by one week.
calAlarm.add(Calendar.DATE, 7);
}