Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the Intent extras for a PendingIntent that is already pending?

I have scheduled a PendingIntent with AlarmManager. When the AlarmManager delivers the Intent, I am able to getExtras() all the data that I originally sent.

However, sometimes I get additional data that I want to pass with the Intent, before the AlarmManager fires. My thought was, I would just get the Intent like I was going to cancel it, but then after cancelling it, update the extras and reschedule it with the AlarmManager, like this:

Intent i=new Intent(this, MyReceiver.class);
Bundle b = i.getExtras();
PendingIntent pi=PendingIntent.getBroadcast(this, id,i, 0);
if (b == null) b = i.getExtras(); // in case I can't get it before calling getBroadcast
// now add a key to b, put it in a new intent, schedule it, and cancel the old one?

I'm calling getBroadcast() with the same id as I schedule it with earlier. The only problem is, when I call getExtras() it always returns null. This seems to be kind of the reverse of the problem I have seen frequently where an Intent will be cached and that is not desired. In this case I actually want to get the cached Intent and get the value for it, and since the Intent is pending it should still be there.

How do I do this?

A couple of ideas I have had and/or tried. One revolves around the Intent.fillIn() function, could I perhaps use this to indicate that it should (or should not) overwrite the extras so that I can retrieve the original ones.

Looking a bit further, I see that PendingIntent has writeToParcel(). Can I use this to get access to the extras of the attached Intent? My attempt failed with readBundle: bad magic number exception on readParcel:

PendingIntent pi=PendingIntent.getBroadcast(this, id,i, 0);
Parcel out = Parcel.obtain();
pi.writeToParcel(out, 0);
i.readFromParcel(out);

I suspect that maybe this is because I am outputting a PendingIntent but trying to read it back as an Intent.

The other idea is that I could call send() on the PendingIntent to cause it to be immediately delivered, passing a new Intent with a new key to add. Then in the handler I would have to iterate through all keys in the extras of the intent. It would then need to re-issue the PendingIntent to the AlarmManager if it wasn't time yet to do the actual processing.

like image 766
Michael Avatar asked Apr 14 '13 20:04

Michael


People also ask

How does Pending Intent work?

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.

What is request code in pending intent?

1- requestCode is used to get the same pending intent later on (for cancelling etc) 2- Yes, they will get override as long as your specify the same Receiver to your Intent that you specify on your PendingIntent.


2 Answers

Try this

pi = PendingIntent.getBroadcast(this, id, i, 
                       PendingIntent.FLAG_UPDATE_CURRENT)

Here we are sending the PendingIntent.FLAG_UPDATE_CURRENT intent flag, if same PendingIntent exists it will be return as is, otherwise a new PendingIntent will be returned.

Please note when we say intent match, URI,Data type, Category will be matched, while intent extras will be ignored while matching. In other words IntentFilters will be matched of both intents.

like image 101
Akhil Avatar answered Oct 04 '22 00:10

Akhil


Ok, I finally found a solution to this problem.

It doesn't seem to be possible to get the Intent from a PendingIntent, but it is possible to add extras in the Intent passed to getBroadcast() - it is important that the last parameter, the flags, be zero so that it won't overwrite the existing extras.

Also, the extras contain name/value pairs, and it is important that the new key added not match a key in the existing Intent. This means that removeExtra() must be called when done to get rid of the key before next time. Then call send() on the PendingIntent targeting oneself, and then when receiving the intent it is possible to access both the new and old extras. Both extras can then be collected into a new Intent and then the AlarmManager can be called to reschedule.

like image 22
Michael Avatar answered Oct 04 '22 00:10

Michael