22

Documentation for PendingIntent.FLAG_NO_CREATE reads:

Flag indicating that if the described PendingIntent does not already exist, then simply return null instead of creating it.

My question: What criteria are used to compare PendingIntents?

I'm guessing under the hood this flag uses PendingIntent.equals, but I'm not really sure what criteria that function is using. Is it using the action, requestCode, categories, extras (I'm guessing no), etc.?

Context:

I want to start an alarm with a pending intent if my alarm is not already setup. Specifically, I'm following this answer.

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);
}
Community
  • 1
  • 1
Steven Wexler
  • 14,113
  • 7
  • 42
  • 75
  • 4
    Nice question. I know this is not right. But, I used to cancel previous alarm and restart it when ever i think it was needed.. I am looking forward to this question's answer. –  Apr 08 '15 at 17:13
  • I guess its requestCode only. Can't you access the source to check it? Android Studio usually does show it. – Stan Apr 08 '15 at 17:25

2 Answers2

29

To determine if 2 PendingIntents match, the following must be equal:

  • The requestCode parameter used when the PendingIntent was created
  • The Intent ACTION
  • The Intent CATEGORIES
  • The Intent DATA
  • The Intent MIMETYPE
  • The Intent PACKAGE
  • The Intent COMPONENT

Extras are not taken into consideration.

You can read more in the PendingIntent summary documentation and Intent.filterEquals().

David Wasser
  • 85,616
  • 15
  • 182
  • 239
2

I'm guessing under the hood this flag uses PendingIntent.equals, but I'm not really sure what criteria that function is using. Is it using the action, requestCode, categories, extras (I'm guessing no), etc.?

Actually the hint is in class description:

A description of an Intent and target action to perform with it. Instances of this class are created with

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

the returned object can be handed to other applications so that they can perform the action you described on your behalf at a later time.

By giving a PendingIntent to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself (with the same permissions and identity). As such, you should be careful about how you build the PendingIntent: almost always, for example, the base Intent you supply should have the component name explicitly set to one of your own components, to ensure it is ultimately sent there and nowhere else.

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.

Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

There are two typical ways to deal with this.

If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to 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), or getService(android.content.Context,int,android.content.Intent,int).

If you only need one PendingIntent active at a time for any of the Intents you will use, then you can alternatively use the flags FLAG_CANCEL_CURRENT or FLAG_UPDATE_CURRENT to either cancel or modify whatever current PendingIntent is associated with the Intent you are supplying.

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

Community
  • 1
  • 1
Stan
  • 6,121
  • 8
  • 48
  • 85
  • I'm asking what this function does: "I'm guessing under the hood this flag uses [PendingIntent.equals](https://github.com/android/platform_frameworks_base/blob/59701b9ba5c453e327bc0e6873a9f6ff87a10391/core/java/android/app/PendingIntent.java#L915), but I'm not really sure what criteria that function is using" – Steven Wexler Apr 08 '15 at 17:28
  • Usually people watch source to understand sucj things and thats why i'm showing it to you. – Stan Apr 08 '15 at 17:31
  • I usually appreciate source code in an answer! It's usually great to help explain/support an answer. But I pasted a link to exactly the code you pasted. I don't understand that code, so I'm looking for an explanation, not just a copy/past of code that I linked to. – Steven Wexler Apr 08 '15 at 17:37
  • Sorry, I din't noticed the link to a method. I was expecting to see its body in your question. – Stan Apr 08 '15 at 17:40
  • The answer is buried in your ~30 lines of quoted text. If you format it I'll give your the check. – Steven Wexler Apr 08 '15 at 19:02
  • You could just visit the url. – Stan Apr 08 '15 at 19:04
  • Ok, I'll write an appropriate answer myself. – Steven Wexler Apr 08 '15 at 19:07
  • It is formatted well enough? Cuz its like on a grepcode without links. – Stan Apr 08 '15 at 19:14