Notification passes old Intent Extras

27,940

Solution 1

You are sending the same request code for your pending intens. Change this:

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

To:

PendingIntent contentIntent = PendingIntent.getActivity(context, UNIQUE_INT_PER_CALL, notificationIntent, 0);

intents are not created if you send the same params. They are reused.

Solution 2

Alternatively, you can use the following code to generate your PendingIntent:

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

From the doc for PendingIntent.FLAG_UPDATE_CURRENT:

If the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.

Solution 3

You are passing the same ID. In this kind of situation, make a unique id from time like this:

int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);

And put it as this:

PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),iUniqueId, intentForNotification, 0);

Solution 4

For anyone looking for the best approach after a long time all, you need to pass the PendingIntent.FLAG_UPDATE_CURRENT as the last argument as shown below

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

you don't even need to provide a new unique id.

You need to do this for next time onwards not for the first time

Share:
27,940
BrianM
Author by

BrianM

Updated on November 09, 2020

Comments

  • BrianM
    BrianM over 3 years

    i am creating a notification inside a BroadcastReceiver via this code:

    String ns = Context.NOTIFICATION_SERVICE;
            NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
            int icon = R.drawable.ic_stat_notification;
            CharSequence tickerText = "New Notification";
            long when = System.currentTimeMillis();
    
            Notification notification = new Notification(icon, tickerText, when);
            notification.defaults |= Notification.DEFAULT_VIBRATE;
            long[] vibrate = {0,100,200,200,200,200};
            notification.vibrate = vibrate;
            notification.flags |= Notification.FLAG_AUTO_CANCEL;
    
            CharSequence contentTitle = "Title";
            CharSequence contentText = "Text";
            Intent notificationIntent = new Intent(context, NotificationActivity.class);
            notificationIntent.putExtra(Global.INTENT_EXTRA_FOO_ID, foo_id);
    PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
    
            notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
    
            int mynotification_id = 1;
    
            mNotificationManager.notify(mynotification_id, notification);
    

    When I click on the notification, it opens the NotificationActivity and inside the Activity i can retrieve the foo_id from the Intent-Bundle (e.g. 1)

    However if another notification is triggered and i click on it again, the activity still receives the "old" value (1) from the Intent-Bundle. I've tried to clear the bundle with clear(), but am receiving the same effect. I think sth is wrong with my code..

  • BrianM
    BrianM over 12 years
    so the UNIQUE_INT_PER_CALL is an Integer I have to provide? or is this a static variable declared somewhere?
  • Najib.Nj
    Najib.Nj over 9 years
    Thanks...perfectly working for this flag which is add "PendingIntent.FLAG_UPDATE_CURRENT" :)
  • William T. Mallard
    William T. Mallard about 9 years
    Worked for me, using pending intent to transfer state from setting an alarm to the broadcast receiver.
  • wal
    wal over 7 years
    android gotcha #147 - so an Intent that has different extras (via putExtra) are considered the same and re-used because i did not provide a unique id to some pending intent call - terrible api
  • exloong
    exloong over 7 years
    why not use new Random().nextInt()
  • Exigente05
    Exigente05 over 7 years
    you know what, I were so careless. Just thinking how could it remain 0 in one block (in my case) :(
  • James McNee
    James McNee over 7 years
    This was incredibly useful for me, just a tip for others, it is likely that you are building your notification in the same method, and so you can just set the id for the new pending intent to the same as the one you are going to use for the notifications unique id!
  • Shruti
    Shruti about 7 years
    @IncrediApp, is it same with PendingIntent.getBroadcast(); ?
  • James Andrew
    James Andrew almost 7 years
    I just wish i knew about what these flags really did before I sent notifications out to my users(!) Glad this resolves my woes...
  • Brill Pappin
    Brill Pappin about 6 years
    That doesn't work, i got here because thats what i was doing.
  • Gentle
    Gentle about 6 years
    You need to do this for next times not for the first time, it will work.
  • AJW
    AJW almost 6 years
    @hderanga what does adding "& 0xfffffff" do to the int above?
  • AJW
    AJW almost 6 years
    Is there any benefit to using "new Random().nextInt()" rather than "System.currentTimeMillis()"?
  • Sam
    Sam almost 6 years
    using random can easily regenerate the same integer value again on accident, thus causing a very hard to find bug of old intents being passed.
  • artman
    artman almost 6 years
    @AJW there was in my case. I created 2 different notifications in exact same millisecond, so one of them got wrong extras.
  • Jordan
    Jordan over 5 years
    @AJW System.currentTimeMillis() returns a long, while the requestId parameter of PendingIntent.getActivity() takes an int. 0xffffffff is a bitmask. While there's a bit more to it, the simple explanation is that doing `long & 0xffffffff' gives the lowest 32-bits from the long and discards the highest 32-bits, leaving you with essentially a 32-bit int. This is better than simply casting to an int because it won't muck up the sign bit (if you cast a long that is bigger than an int to an int the sign bit will overflow and you'll potentially wind up with a negative value)