Where are stored PendingIntents? Big trap of using - android

In my project i have tried out some possibilities and limitations of PendingIntent
So i have created some notification, that opens an activity by tapping
Intent intent = new Intent(this, NotificationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(Constants.INTENT_ITEM_NAME, "ItemName");
intent.putExtra(Constants.INTENT_ITEM_ID, itemId);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
// properties set
;
notificationManager.notify(new Random().nextInt(10), notificationBuilder.build());
at begin was everithing good, until i have placed other item to show in NotificationActivity by tap on notification.
Here starts problems: in NotificationActivity was still showed previous item.
After some search it could be solved with:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
BUT: if i have in same time many notifications, then i always see only last item, PendingIntent was created for.
Second parameter of getActivity is requestCode. So when i update solution to
PendingIntent pendingIntent = PendingIntent.getActivity(this, new Random().nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then also many items are supported, and if for some reason the random makes me same numbers, the content in NotificationActivity will be the same.
So to 99% the solution is good, yes? NO
Again to first approach
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
If i set new extras for intent -> old extras will be readed.
In other words: by new Random().nextInt(1000) somewhere in the system of android device will be stored till 1000 PendingIntents for one of activities i have forever
So here are the questions:
Where all this PendingIntents stored?
How to clear it?
With How to clear it, i mean a way to remove all currently maked PendingIntents with some Random as requestCode, so that in clear way with only one notification at time i could use
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
with different items

PendingIntents are stored in non-persistent storage. When the device restarts, they are all gone.
Also, if you create a PendingIntent and put it in a Notification, once the Notification is gone (dismissed, opened, etc.) the PendingIntent is no longer in use and will be deleted.
Generally you should not use random numbers for the requestCode as this is no guarantee of uniqueness. You need to find a way to make your PendingIntent unique if you want to have many of them existing in parallel.

Related

What is the meaning of use FLAG_ONE_SHOT in a pendingintent which will be used to a notification? Is it necessary?

Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setContentIntent(pendingIntent);
Does it mean that I can't jump to the mainActivity multiple times by repeatedly clicking this notification? Is pendingIntent.send() called internally when I clicks the notification? Does this flag become meaningless in the notifications?
PendingIntent.FLAG_ONE_SHOT means that the PendingIntent will be deleted after it is used once. Normally, a PendingIntent can hang around if there are other references to it in the system.
This flag can be used to prevent multiple uses of the PendingIntent, although my personal experience is that this flag generally causes more problems than it solves.
You asked:
Is pendingIntent.send() called internally when I clicks the notification?
Yes, that's basically what happens when you click on the UI element associated with the PendingIntent in the Notification.

android pendingintent sending duplicate data

My PendingIntent is working on time broadcast receiver. The problem is when I set my time and send first data it work successfully but when I send other data it again displays the first data and not the new one, below is my code.
All my mServiceIntenyt code is perfect but what is the error
mServiceIntent.putExtra("unique",lackmyData);
PendingIntent pintent = PendingIntent.getService(MessageActivity.this, 0, mServiceIntent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP,targetCal.getTimeInMillis(), pintent);
If you do not pass any flag then the PendingIntent ignores changes in extras when comparing Intent, causing the same old Intent to be spent again. You need to ask the PendingIntent to update the Intent as below:
PendingIntent pintent = PendingIntent.getService(MessageActivity.this,
0, mServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Or in order to make sure your intent is unqiue based on extras, you may play with setData as below:
mServiceIntent.setData(Uri.parse(mServiceIntent.toUri(Intent.URI_INTENT_SCHEME)));

Intent/action from notification not passed on when user clicks on notification

I'm developing an app that displays notifications when there's an incoming event. When the user clicks on the notifications, they will be brought to an activity with a specific fragments within the app. On a Samsung Galaxy Note 2 with Android 4.1.2, this works. However, on a Samsung Galaxy S3 with Android 4.3, the activity does not receive the correct action, but rather receives the intent "android.intent.action.MAIN".
Also, the S3 doesn't seem to get the extras that I'm putting in the intent either. The Note 2 receives them fine.
The notification code is as follows:
Intent launchIntent;
String myType, myAction;
// myType and myAction are programmatically set
launchIntent = new Intent(context, MainActivity.class);
launchIntent.putExtra("Type", myType);
launchIntent.setAction(myAction);
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder noti = new NotificationCompat.Builder(
context).setContentTitle(context.getResources().getString(R.string.app_name))
setContentText(notificationMessage)
setSmallIcon(R.drawable.ic_stat_notify)
setContentIntent(pendingIntent)
setAutoCancel(true)
setWhen(System.currentTimeMillis())
setDefaults(Notification.DEFAULT_ALL);
notificationManager.notify(notifyId, noti.build());
Does anyone know why it works with 1 device and not another? Are there any changes in intent from 4.1 to 4.3?
Thanks.
OK, turns out I need to set my intent flags to "Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP" for it to work.
There are problems on some devices when the requestCode in the PendingIntent is not > 0. There are even some devices where the requestCode needs to be > 1000.
Change this:
PendingIntent.getActivity(context, -1, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to this:
PendingIntent.getActivity(context, 1001, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Cancelling a PendingIntent with unique requestCode

I'm having trouble with cancelling my pendingintent. Right now I create my pending intent like so:
Intent intent = new Intent(_self, NotificationService.class);
PendingIntent pi = PendingIntent.getService(this, task.getID, intent, 0);
task.getID is a unique int here. Later on in my app a user can edit a "task" and can decide to cancel the notifications (pendingintent). I try to cancel the pendingintent like so:
Intent intent = new Intent(_self, NotificationService.class); PendingIntent pIntent = PendingIntent.getBroadcast(_self, task.getID, intent , PendingIntent.FLAG_NO_CREATE);
pIntent.cancel();
But it doens't work! The notifications still shows up. In this case, task.getID refers to the unique id that was created before.
I've tried several different parameters, PendingIntent.FLAG_NO_CREATE returns null, FLAG_UPDATE_CURRENT doens't work and FLAG_CANCEL_CURRENT neither. Can somebody please help me with this and see what it is I am doing wrong?
You are trying to create a service with your PendingIntent and are trying to cancel a Broadcast. It will never work.
You need to getService with the PendingIntent you are trying to cancel.
You need to recreate your pending intent THE EXACT SAME WAY you created the first one when you want to cancel it.
take a look : Cancelling a PendingIntent

android pending intent notification problem

I have a alarm thing going on in my app and it launches a notification that then when pressed launched an activity.
The problem is that when I create more than one alarm then the activity launched from the notification gets the same extras as the first one. I think the problem is either with the intent i put in the pending intent or in the pending intent itself. I think I might need to put a flag on one of these but I dont know which one.
Intent showIntent =new Intent(context, notificationreceiver.class);
showIntent.putExtra("details", alarmname);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
showIntent, 0);
notification.setLatestEventInfo(context, "The event is imminent",
alarmname, contentIntent);
And the receiver of the notification
Bundle b = getIntent().getExtras();
String eventname = b.getString("details");
details.setText(eventname);
The "details" extra is the same to every the next time a notification happens instead of having the different value.
Until I set the intents I am sure that the correct value goes to the "details" so its a problem of getting the first intent everytime i press any notification.
How can I make it to launch the correct intents?
Hope I was as clear as i could
Thanks!
The way I solved that problem was by assigning a unique requestCode when you get the PendingIntent:
PendingIntent.getActivity(context, requestCode, showIntent, 0);
By doing so you are registering with the system different/unique intent instances.
Tip: A good way of making the requestCode unique would be by passing to it the current system time.
int requestID = (int) System.currentTimeMillis();
The problem is that when I create more
than one alarm then the activity
launched from the notification gets
the same extras as the first one.
Correct.
How can I make it to launch the
correct intents?
That depends on whether you have two alarms that will be registered at once, or not.
If not, you can use FLAG_ONE_SHOT or one of the other PendingIntent flags to have your second PendingIntent use the newer extras.
If, however, you will have two alarms registered at once, with different Intent extras, you will need to make the two Intents be more materially different, such that filterEquals() returns false when comparing the two. For example, you could call setData() or setAction() and provide different values for each Intent.
I had this issue in my app and just generated a random number to over come overriding notifications intent:
int random= new Random().nextInt();
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
random,
PendingIntent.FLAG_UPDATE_CURRENT
);
I followed the solution provided by U-ramos and this worked for me
int requestID = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestID, showIntent, 0);
another solution:
use the PendingIntent.FLAG_UPDATE_CURRENT like this:
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,i, PendingIntent.FLAG_UPDATE_CURRENT);
this worked for me

Categories

Resources