Alarm Notification fires instantly. Android

后端 未结 5 2030
忘掉有多难
忘掉有多难 2021-02-15 18:15

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

相关标签:
5条回答
  • 2021-02-15 18:47

    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
    
    }
    
    0 讨论(0)
  • 2021-02-15 18:54

    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);
        }
    
    }
    
    0 讨论(0)
  • 2021-02-15 19:06

    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();
    
        }
    
    0 讨论(0)
  • 2021-02-15 19:08

    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

    0 讨论(0)
  • 2021-02-15 19:11

    Problem

    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.

    Update

    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);
    }
    
    0 讨论(0)
提交回复
热议问题