64

A few days ago I was struggling to find a way to use custom intents for my alarms. Although I got clear answer that I have to customize the Intents based on some unique ID eg. setAction() still have some problems.

I define a PendingIntent this way:

Intent intent = new Intent(this, viewContactQuick.class);
intent.setAction("newmessage"+objContact.getId());//unique per contact
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK ).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP );
intent.putExtra("id", Long.parseLong(objContact.getId()));
intent.putExtra("results", result.toArray());

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0);

then this is used by a notification manager

NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
// first try to clear any active notification with this contact ID
mNotificationManager.cancel(Integer.parseInt(objContact.getId()));

// then raise a new notification for this contact ID
mNotificationManager.notify(Integer.parseInt(objContact.getId()), notification);

This works like this:

  • application creates a message for a contact
  • an intent is provided with the contact id and details about the message
  • notification is raised with the message
  • user actiones on the notification and the app displays the message passed by the intent

The problem

This can happen more than once for a contact. And when the second message is generated, the notification is raised well (message is fine there) but the intent when the user actions the notification it uses old data, so previous message is passed and not the brand new message.

So someway the intent is caching and reusing previous extras. How can I make it unique per contact and per action?

Pentium10
  • 204,586
  • 122
  • 423
  • 502
  • Is there a way to clear all cached IntentExtras? I assume I fixed it now, but older cached Intents still remain... – OneWorld Dec 10 '10 at 10:22
  • A similar issue can arise depending on the Intent's flags or an activity's launchMode. In this case, you'll need to check [Activity::onNewIntent](http://j.mp/ieXMCA), because Activity::getIntent will return the Activity's ORIGINAL intent, not the new intent with the updated action/extras/etc. – brack Jan 07 '11 at 19:44

3 Answers3

103

If only one of your PendingIntents for this contact will be outstanding at any point in time, or if you always want to use the latest set of extras, use FLAG_UPDATE_CURRENT when you create the PendingIntent.

If more than one contact-specific PendingIntent will be outstanding at once, and they need to have separate extras, you will need to add a count or timestamp or something to distinguish them.

intent.setAction("actionstring" + System.currentTimeMillis());

UPDATE

Also, the lightly-documented second parameter to getActivity() and kin on PendingIntent apparently can be used to create distinct PendingIntent objects for the same underlying Intent, though I have never tried this.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    I ended up adding a timestamp to the action. – Pentium10 Jul 05 '10 at 13:18
  • 1
    awesome! i used my current widget id to seperate them ( also allowing some level of caching ). – DavidG Sep 13 '11 at 10:35
  • I have a quick question about `setAction()`. What does it do exactly? I looked at the Doc, but it was still a bit confusing. – Andy Jul 11 '12 at 06:38
  • @Andy: `setAction()`, um, sets the action. The action is normally used with implicit `Intent`s (think `ACTION_VIEW` to bring up an activity to go view something). If your `Intent` specifies the destination component (e.g., `new Intent(this, Something.class)`), the action is not used for routing purposes, but it still comes along for the ride. And, the action is one of the things that is used to determine whether one `Intent` is equivalent to another. – CommonsWare Jul 11 '12 at 09:36
  • 1
    Great answer! I can confirm that setting the second parameter to getActivity() to a random integer solves this problem. Too bad it is a deprecated parameter? – IgorGanapolsky Oct 22 '12 at 00:31
  • 4
    @IgorG.: That parameter is not deprecated. The documentation claims that it is unused, but the documentation is obviously flawed in this area. – CommonsWare Oct 22 '12 at 00:33
  • I thought that was why filterEquals() and filterHashCode() existed. It seems they no longer work: http://stackoverflow.com/questions/13553911/intent-filterequals-and-filterhashcode-are-no-longer-invoked-when-creating-pendi – AlikElzin-kilaka Nov 25 '12 at 18:51
  • I can also confirm that updating the second parameter indeed makes each Intent and PendingIntent unique. – Soham Nov 27 '12 at 19:22
  • Here is the link to PendingIntent Class for setting the flag: https://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT – david Oct 13 '16 at 00:55
40

I usually specify unique requestCode to prevent my PendingIntents from overriding each other:

PendingIntent pending = PendingIntent.getService(context, unique_id, intent, 0);

And in your case I agree with CommonsWare you just need FLAG_UPDATE_CURRENT flag. New extras will override old values.

Fedor
  • 43,261
  • 10
  • 79
  • 89
  • 1
    That is not enough to keep your PendingIntent's from colliding with each other. You must also use PendingIntent.FLAG_UPDATE_CURRENT – IgorGanapolsky Oct 29 '12 at 14:47
  • and to generate a unique_id here is good solution `int unique_id = (int) System.currentTimeMillis();` – Glenn Sonna Feb 23 '15 at 15:00
  • I'm not sure that you can use a Long there, or actually an arbitrary random Int for that matter. IIRC, Android will throw an exception if you use any of the bits in the "larger" byte for request codes, which basically limits you to small, positive numbers. – milosmns Jan 10 '20 at 17:53
  • Yeah found it, something like this - https://stackoverflow.com/questions/33331073/android-what-to-choose-for-requestcode-values – milosmns Jan 10 '20 at 17:53
0

Found a simple solution, trick is the request code.

int requestCode = (int) System.currentTimeMillis();

PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);

If you will use same request code for each PendingIntent Android will consider it as same request which will return same Extras which you put in your first request.