Я работаю над напоминанием, которое отправляет пользователю уведомление в установленное время.

Тревога срабатывает мгновенно ...

Я пробовал большинство предложений из stackoverflow, но все еще имел ту же проблему

Пожалуйста, помогите мне решить эту проблему.

данные сервера

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

снимок экрана

enter image description here

8
karthik kolanji 1 Сен 2017 в 15:48

5 ответов

Лучший ответ

Наконец, я нашел способ сделать это, сохранив PendingIntent requestCode в базе данных (использовал ROOM), а затем отменив все тревоги, получив все requestCode из 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();

    }
-1
karthik kolanji 18 Сен 2017 в 11:50

Основная проблема заключается в этой строке:

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

Вам нужно понять, что это просто установка Дня недели, который будет отображаться в выходных данных. Он не меняет основную дату для соответствия, что, я думаю, именно то, что вы ожидаете.

Попробуйте использовать следующий код, чтобы изменить даты, чтобы установить будильник для каждого выбранного дня:

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

}
1
Nick Cardoso 12 Сен 2017 в 13:48

У меня есть такая же проблема, пожалуйста, проверьте следующие детали:

Не работает пример кода:

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

Это делается только тогда, когда вы собираетесь установить повторение, вам нужно проверить, прошло ли оно или нет, и если оно прошло, просто добавьте требуемое время для повторения

0
Wael Abo-Aishah 13 Сен 2017 в 17:01

Попал в ту же проблему и наткнулся на этот вопрос, находя решение. При настройке будильника Вам просто нужно проверить, что дата будильника не должна быть раньше текущей.

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
Hussnain Azam 26 Сен 2019 в 10:54

Проблема

Ваш будильник сработает мгновенно, потому что Android сработает от любых будильников, которые были запланированы в прошлом.

Некоторые из ваших сигналов тревоги планируются в прошлом, потому что следующий код работает не так, как вы ожидаете. Пример кода из вашего вопроса:

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

В приведенном выше коде вы добавляете к своему будильнику только один день, если он был в прошлом. Допустим, вы запускаете этот код в пятницу и читаете сигнал тревоги в понедельник. Ваш код прибавит один день к дате, ставшей вторником, и запланируйте эту тревогу. Тревога в прошлом, потому что вторник все еще до пятницы, поэтому Android сработает от этой тревоги вскоре после того, как запланировано.

Обновить

Из вашего вопроса неясно, что вы хотите сделать с напоминаниями, которые были в прошлом. Одно из возможных решений - запланировать их на 1 неделю в будущем.

if(calAlarm.before(calNow)) 
{
   // If it's in the past increment by one week.
   calAlarm.add(Calendar.DATE, 7);
}
1
Newtron Labs 8 Сен 2017 в 16:11