警报通知立即启动。 Android的

我正在处理提醒,将固定时间的通知发送给用户。

闹钟正在下车

我尝试了大部分的build议,但仍然有相同的问题

请帮我解决这个问题。

服务器数据

 user_reminder": [ { "id": "75", "name": "Morning Snacks", "time": "11:00:00", "days": "1,2,3,4,5,6,7", "user_id": "14" }, { "id": "76", "name": "Lunch", "time": "13:00:00", "days": "1,2,3,4,5,6,7", "user_id": "14" }, ...... ] 

我的代码

 for (int i = 0; i < reminderList.size(); i++) { String time = reminderList.get(i).getTime(); // "time": "11:00:00" String strSpit[] = time.split(":"); String strDays[] = reminderList.get(i).getDays().split(","); //"days": "1,2,3,4,5,6,7" Date date = new Date(); Calendar calNow = Calendar.getInstance(); calNow.setTime(date); Calendar calAlarm = Calendar.getInstance(); calAlarm.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0])); calAlarm.set(Calendar.MINUTE, Integer.parseInt(strSpit[1])); for (int j = 0; j < strDays.length; j++) { calAlarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j])); if (calAlarm.before(calNow)) { //if its in the past increment calAlarm.add(Calendar.DATE, 1); } notifyIntent.putExtra(Constants.REMINDER_NAME, reminderList.get(i).getName()); pendingIntent = PendingIntent.getBroadcast(this, 0, notifyIntent, PendingIntent.FLAG_ONE_SHOT); alarmManager.set(AlarmManager.RTC_WAKEUP, calAlarm.getTimeInMillis() , pendingIntent); } } } 

获取天数 :这解决了当天的编号

 public int getDayInt(String strDay) { int dayNumber = 0; if (strDay.equals("1")) { dayNumber = Calendar.MONDAY; } ...... return dayNumber; } 

屏幕截图

在这里输入图像说明

Solutions Collecting From Web of "警报通知立即启动。 Android的"

主要的问题似乎是这一行:

 calAlarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j])); 

你需要意识到的是,这只是设置将在输出中显示的星期几 – 它不会改变匹配的基础date,我认为这是你所期待的。

尝试使用以下代码来更改date,以便为选定的每一天设置闹钟:

 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 } 

问题

您的警报即将closures,因为Android会触发过去计划的任何警报。

过去,您的某些警报正在计划中,因为以下代码不能按预期工作。 来自您的问题的示例代码:

 if (calAlarm.before(calNow)) { //if [it's] in the past increment calAlarm.add(Calendar.DATE, 1); } 

在上面的代码中,如果警报是过去的,那么您只能在警报中添加一天。 假设您周五正在运行此代码,并且您读了星期一的闹钟。 您的代码将在星期二添加一天,安排该警报。 由于星期二还在星期五之前,闹钟已经过去了,所以Android会在计划后不久就会触发闹钟。

更新

从你的问题来看,你还不清楚你想用过去的提醒来做什么。 一个可能的解决scheme是安排他们在未来1周。

 if(calAlarm.before(calNow)) { // If it's in the past increment by one week. calAlarm.add(Calendar.DATE, 7); } 

我之前有同样的问题,请检查以下的细节:

不工作的代码示例:

 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); 

工作代码:

  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); } 

只有当你要重复设置的时候才会这样做,你需要检查它是否被通过,如果通过,只需要添加所需的时间来重复

最后,我find了一种方法,通过在数据库中存储PendingIntent requestCode (使用ROOM),然后通过从DB检索所有的requestCode来取消所有的警报

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(); }