Android keeps caching my intents Extras, how to declare a pending intent that keeps fresh extras?
Asked Answered
I

3

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?

Iou answered 29/6, 2010 at 11:12 Comment(2)
Is there a way to clear all cached IntentExtras? I assume I fixed it now, but older cached Intents still remain...Diu
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, because Activity::getIntent will return the Activity's ORIGINAL intent, not the new intent with the updated action/extras/etc.Unfleshly
R
102

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.

Rajab answered 29/6, 2010 at 11:56 Comment(9)
I ended up adding a timestamp to the action.Iou
awesome! i used my current widget id to seperate them ( also allowing some level of caching ).Neumeyer
I have a quick question about setAction(). What does it do exactly? I looked at the Doc, but it was still a bit confusing.Puri
@Andy: setAction(), um, sets the action. The action is normally used with implicit Intents (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.Rajab
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?Antevert
@IgorG.: That parameter is not deprecated. The documentation claims that it is unused, but the documentation is obviously flawed in this area.Rajab
I thought that was why filterEquals() and filterHashCode() existed. It seems they no longer work: #13554411Dorsey
I can also confirm that updating the second parameter indeed makes each Intent and PendingIntent unique.Aerobatics
Here is the link to PendingIntent Class for setting the flag: developer.android.com/reference/android/app/…Federico
A
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.

Antimony answered 29/6, 2010 at 12:16 Comment(4)
That is not enough to keep your PendingIntent's from colliding with each other. You must also use PendingIntent.FLAG_UPDATE_CURRENTAntevert
and to generate a unique_id here is good solution int unique_id = (int) System.currentTimeMillis();Lumberman
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.Underling
Yeah found it, something like this - #33331573Underling
R
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.

Ruthie answered 18/7, 2023 at 21:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.