Как Android сравнивает ожидающие намерения

Документация для PendingIntent.FLAG_NO_CREATE гласит:

Флаг, указывающий, что если описанный PendingIntent еще не существует, то просто вернуть null вместо его создания.

Мой вопрос: Какие критерии используются для сравнения PendingIntents?

Я предполагаю, что под капотом этот флаг использует PendingIntent.equals, но я не уверен, какие критерии использует эта функция. Использует ли он действие, код запроса, категории, дополнительные функции (думаю, нет) и т. д.?

Контекст:

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

Intent i = new Intent(applicationContext, MyService.class);
i.setAction("myAction");
PendingIntent pi = PendingIntent.getService(applicationContext, /*requestCode*/0, i, PendingIntent.FLAG_NO_CREATE);
if (pi != null) {
  AlarmManager alarmMgr = (AlarmManager)applicationContext.getSystemService(Context.AlarmService);
  alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, AlarmManager.INTERVAL_HOUR, AlarmManager.INTERVAL_HOUR, pi);
}

person Steven Wexler    schedule 08.04.2015    source источник
comment
Хороший вопрос. Я знаю, что это неправильно. Но раньше я отменял предыдущую тревогу и перезапускал ее, когда считал, что это необходимо. Я с нетерпением жду ответа на этот вопрос.   -  person    schedule 08.04.2015
comment
Я думаю, это только requestCode. Вы не можете получить доступ к источнику, чтобы проверить его? Android Studio обычно показывает это.   -  person Stan    schedule 08.04.2015


Ответы (2)


Чтобы определить, совпадают ли 2 PendingIntents, следующее должно быть равно:

  • Параметр requestCode, используемый при создании PendingIntent
  • Intent АКЦИЯ
  • Intent КАТЕГОРИИ
  • Intent ДАННЫЕ
  • Intent MIMETYPE
  • ПАКЕТ Intent
  • КОМПОНЕНТ Intent

Дополнения не учитываются.

Дополнительную информацию можно найти в сводной документации по PendingIntent и Intent.filterEquals().

person David Wasser    schedule 12.04.2015

Я предполагаю, что под капотом этот флаг использует PendingIntent.equals, но я не совсем уверен, какие критерии использует эта функция. Использует ли он действие, код запроса, категории, дополнительные функции (думаю, нет) и т. д.?

На самом деле подсказка находится в описании класса:

Описание намерения и целевого действия, которое необходимо выполнить с ним. Экземпляры этого класса создаются с помощью

getActivity(android.content.Context,int,android.content.Intent,int), getActivities(android.content.Context,int,android.content.Intent[],int), getBroadcast(android.content.Context,int, android.content.Intent,int), getService(android.content.Context,int,android.content.Intent,int);

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

Предоставляя PendingIntent другому приложению, вы предоставляете ему право выполнять указанную вами операцию, как если бы это другое приложение было вами (с теми же разрешениями и идентификатором). Таким образом, вы должны быть осторожны с тем, как вы создаете PendingIntent: почти всегда, например, базовое намерение, которое вы предоставляете, должно иметь имя компонента, явно установленное для одного из ваших собственных компонентов, чтобы гарантировать, что в конечном итоге он будет отправлен туда и никуда больше.

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

Из-за такого поведения важно знать, когда два Intent считаются одинаковыми для получения PendingIntent. Распространенной ошибкой людей является создание нескольких объектов PendingIntent с намерениями, которые различаются только своим дополнительным содержимым, ожидая каждый раз получать разные PendingIntent. Этого не происходит. Части намерения, которые используются для сопоставления, — это те же части, которые определены в Intent.filterEquals. Если вы используете два объекта Intent, которые эквивалентны Intent.filterEquals, вы получите один и тот же PendingIntent для обоих из них.

Есть два типичных способа справиться с этим.

Если вам действительно нужно несколько разных объектов PendingIntent, активных одновременно (например, для использования в качестве двух уведомлений, которые отображаются одновременно), вам нужно убедиться, что в них есть что-то другое, чтобы связать их с разными Ожидающие намерения. Это может быть любой из атрибутов Intent, рассматриваемых Intent.filterEquals, или различные целые числа кода запроса, предоставленные для getActivity(android.content.Context,int,android.content.Intent,int), getActivities(android.content.Context,int, android.content.Intent[],int), getBroadcast(android.content.Context,int,android.content.Intent,int) или getService(android.content.Context,int,android.content.Intent,int).

Если вам нужен только один PendingIntent, активный одновременно для любого из намерений, которые вы будете использовать, вы можете в качестве альтернативы использовать флаги FLAG_CANCEL_CURRENT или FLAG_UPDATE_CURRENT, чтобы либо отменить, либо изменить любой текущий PendingIntent, связанный с намерением, которое вы предоставляете.

из: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.0_r1/android/app/PendingIntent.java#PendingIntent

person Stan    schedule 08.04.2015
comment
Я спрашиваю, что делает эта функция: я предполагаю, что под капотом этот флаг использует PendingIntent.equals, но я не совсем уверен, какие критерии использует эта функция - person Steven Wexler; 08.04.2015
comment
Обычно люди смотрят исходники, чтобы понять такие вещи, поэтому я показываю их вам. - person Stan; 08.04.2015
comment
Обычно я ценю исходный код в ответе! Обычно здорово помочь объяснить / поддержать ответ. Но я вставил ссылку именно на код, который вы вставили. Я не понимаю этот код, поэтому я ищу объяснение, а не просто копию/прошлый код, на который я ссылался. - person Steven Wexler; 08.04.2015
comment
Извините, не заметил ссылку на метод. Я ожидал увидеть его тело в вашем вопросе. - person Stan; 08.04.2015
comment
Ответ скрыт в ваших ~ 30 строках цитируемого текста. Если вы отформатируете его, я дам вам чек. - person Steven Wexler; 08.04.2015
comment
Вы можете просто посетить URL. - person Stan; 08.04.2015
comment
Хорошо, я сам напишу соответствующий ответ. - person Steven Wexler; 08.04.2015
comment
Он достаточно хорошо отформатирован? Потому что это похоже на grepcode без ссылок. - person Stan; 08.04.2015