How does android compare pending intents-ThrowExceptions

Exception or error:

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);
}
How to solve:

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().

###

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

Leave a Reply

Your email address will not be published. Required fields are marked *