Возможно ли создать несколько PendingIntents с тем же кодом requestCode и разными дополнительными функциями?

Я использую AlarmManager для планирования где угодно между 1 и 35 сигналами тревоги (в зависимости от ввода пользователем). Когда пользователь запрашивает расписание новых аварийных сигналов, мне нужно отменить текущие аварийные сигналы, поэтому я создаю все свои аварийные сигналы с одним и тем же кодом запроса, определенным в переменной final.

// clear remaining alarms
Intent intentstop = new Intent(this, NDService.class);
PendingIntent senderstop = PendingIntent.getService(this,
            NODIR_REQUESTCODE, intentstop, 0);
am.cancel(senderstop);

// loop through days
if (sched_slider.getBooleanValue())
for (int day = 1; day < 8; day++) {

    if (day == 1 && sun.isChecked())
                scheduleDay(day);
    if (day == 2 && mon.isChecked())
                scheduleDay(day);
    if (day == 3 && tue.isChecked())
                scheduleDay(day);
    if (day == 4 && wed.isChecked())
                scheduleDay(day);
    if (day == 5 && thu.isChecked())
                scheduleDay(day);
    if (day == 6 && fri.isChecked())
                scheduleDay(day);
    if (day == 7 && sat.isChecked())
                scheduleDay(day);
}

...

public void scheduleDay(int dayofweek) {
    Intent toolintent = new Intent(this, NDService.class);
    toolintent.putExtra("TOOL", "this value changes occasionally");
    PendingIntent pi = PendingIntent.getService(this,
                NODIR_REQUESTCODE, toolintent, 0);
    calendar.set(Calendar.DAY_OF_WEEK, dayofweek);
    calendar.set(Calendar.HOUR_OF_DAY, hour);
    calendar.set(Calendar.MINUTE, minute);
    calendar.set(Calendar.SECOND, 0);
    am.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY * 7, pi);
}

Здесь, если пользователь имеет sun (который является CheckBox), он будет планировать будильник, который будет выполняться каждое воскресенье в hour и minute. Вы можете видеть, что каждый созданный таким образом аварийный сигнал имеет один и тот же requestCode, но TOOL дополнительно изменяется для каждого аварийного сигнала.

Однако, в моем тестировании, когда будильник отключается, и моя служба работает, дополнительные функции от намерения теперь null. Этот вопрос предполагает, что использование PendingIntent.FLAG_CANCEL_CURRENT решит это, но не отменило бы другие PendingIntents?

Короче:

Может ли кто-нибудь объяснить, как работает PendingIntents, в отношении создания нескольких из них с одним и тем же кодом запроса и различными дополнительными функциями? Какие флаги (если есть) я должен использовать?

Ответы

Ответ 1

Собственно, вы не создаете PendingIntent s. Вы запрашиваете их из фреймворка Android. Когда вы запрашиваете PendingIntent из фреймворка Android, он проверяет, есть ли уже PendingIntent, который соответствует критериям, которые вы передаете в качестве аргументов. Если это так, он не создает новый PendingIntent, он просто возвращает вам "токен" , указывающий на существующий PendingIntent. Если он не найдет подходящий PendingIntent, он создаст один, а затем вернет вам "токен" , который указывает на тот, который он только что создал. Есть несколько флагов, которые вы можете изменить, чтобы изменить это поведение, но не так много. Самое главное, чтобы понять здесь, это то, как платформа Android выполняет сопоставление.

Для этого выполняется проверка соответствия следующих параметров (сравнение существующего PendingIntent с параметрами, которые вы прошли):

  • Коды запросов должны быть одинаковыми. В противном случае они не совпадают.
  • "Действие" в Intent должно быть одинаковым (или оба нуля). В противном случае они не совпадают.
  • "Данные" в Intent должны быть одинаковыми (или оба нуля). В противном случае они не совпадают.
  • "Тип" (данных) в Intent должен быть одинаковым (или оба нуля). В противном случае они не совпадают.
  • "Пакет" и/или "компонент" в Intent должны быть одинаковыми (или обеими). В противном случае они не совпадают. Поля "package" и "component" установлены для "явного" Intent s.
  • Список "категорий" в Intent должен быть одинаковым. В противном случае они не совпадают.

Вы должны заметить, что "дополнительные функции" не указаны в списке выше. Это означает, что если вы запрашиваете PendingIntent, "дополнительные" не учитываются, когда фреймворк Android пытается найти соответствующий PendingIntent. Это распространенная ошибка, которую разработчики делают.

Теперь мы можем обратиться к дополнительным флагам, которые вы можете добавить, чтобы изменить поведение запроса PendingIntent:

FLAG_CANCEL_CURRENT - Когда вы укажете этот флаг, если найден соответствующий PendingIntent, то PendingIntent отменяется (удаляется, удаляется, аннулируется) и создается новый. Это означает, что любые приложения, содержащие "токен" , указывающие на старый PendingIntent, не смогут его использовать, поскольку он больше не действителен.

FLAG_NO_CREATE - Когда вы укажете этот флаг, если найден соответствующий PendingIntent, возвращается "токен" , указывающий на существующий PendingIntent (это обычное поведение). Однако, если не найдено соответствия PendingIntent, новый не создается, и вызов просто возвращает null. Это можно использовать для определения наличия активного PendingIntent для определенного набора параметров.

FLAG_ONE_SHOT - Когда вы укажете этот флаг, созданный PendingIntent может использоваться только один раз. Это означает, что если вы дадите "токен" для этого PendingIntent для нескольких приложений, то после первого использования PendingIntent он будет отменен (удален, удален, недействителен), чтобы всякая будущая попытка его использования не удалась.

FLAG_UPDATE_CURRENT - Когда вы укажете этот флаг, если найден соответствующий PendingIntent, "дополнительные" в этом PendingIntent будут заменены "дополнительными" в Intent, которые вы передаете в качестве параметра к методу getxxx(). Если не найдено соответствия PendingIntent, создается новый (это нормальное поведение). Это можно использовать для изменения "дополнительных" в существующем PendingIntent, где вы уже дали "токен" другим приложениям, и не хотите лишить личность существующего PendingIntent.

Позвольте мне попытаться решить вашу конкретную проблему:

В системе не может быть более одного активного PendingIntent, если параметры кода запроса, действия, данных, типа и пакета/компонента одинаковы. Таким образом, ваше требование иметь до 35 активных PendingIntent всех с одинаковым кодом запроса, действиями, данными, типом и параметрами пакета/компонента, но с разными "дополнительными функциями", невозможно.

Я бы предположил, что вы либо используете 35 разных кодов запросов, либо создаете 35 различных уникальных параметров действия для вашего Intent.

Ответ 2

Да, можно просто поместить уникальное действие для для каждого сигнала тревоги

intent.setAction( "uniqueCode" );

Intent intent = new Intent(context, MyAlarmReciver.class);
intent.setAction("uniqueCode");
PendingIntent pendingIntent = PendingIntent.getBroadcast(activity, 0,   intent, 0);
AlarmManager alarmManager = (AlarmManager)       context.getSystemService(activity.ALARM_SERVICE);
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 1);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),   pendingIntent);