android pending intent notification problem - android

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

Related

Where are stored PendingIntents? Big trap of using

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.

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

intent extras are duplicated when using FLAG_UPDATE_CURRENT in PendingIntent when creating android notifications

I want to create several notifications that launches an activity (or refresh it) to display a product description.
Notification notification = new Notification(R.drawable.applicationicon,
Resources.getString("NewSaleNotification", context),
System.currentTimeMillis());
// Hide the notification after its selected
notification.flags |= Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(context, MainApplication.class);
intent.putExtra("saleid", saleid);
// to be sure the activity won't be restarted
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(context, SaleTitle, SaleMessage, pendingIntent);
notificationManager.notify(saleid, notification);
When I create the PendingIntent, I have 4 choices : FLAG_CANCEL_CURRENT, FLAG_NO_CREATE, FLAG_ONE_SHOT and FLAG_UPDATE_CURRENT.
The definition of the last one (http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT) is what I want to do but it doesn't work as it should. If I create 2 notifications, they both have the same 'saleid' extra which is the latest one. How can I make more than one notification with different 'saleid' extra?
but it doesn't work as it should
Yes, it does.
If I create 2 notifications, they both have the same 'saleid' extra which is the latest one.
This is precisely what the documentation says is supposed to happen.
How can I make more than one notification with differents 'saleid' extra?
Option #1: Put a different action string in each of your Intents. This will make them different (from the standpoint of filterEquals()) and give them separate PendingIntents. However, since you are specifying the component in the Intent (MainApplication.class), the action will not affect how the Intent is routed.
Option #2: Use a different requestCode (2nd parameter) on your getActivity() calls. While this is documented as "currently not used", it does result in different PendingIntent objects being returned. However, since this behavior is undocumented, it may change in the future.

How do I cancel Pending Intents in a Android Widget?

I've got some weird behavior and I can only assume is because of the Pending intents I am using.
Scenario
I have a widget (4x1) which has 4 buttons. Within onUpdate of the widget, I add an pending intent for each button. My intents fires a Service with a bundeled parameter and depending on this parameter starts something. I attach intents as this:
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Bundle b = new Bundle();
b.putString("myVariable", someVariable);
Intent intent = new Intent(context, AppStarterService.class);
intent.putExtras(b);
PendingIntent pendingIntent = PendingIntent.getService(context, buttopnPosition, intent, 0);
views.setOnClickPendingIntent(R.id.btnOne, pendingIntent);
The problem
The code works just fine, until the user decides to update the content of the button. Then, a new Pending Intent is done. So, when I press again the button, sometimes it still executes the old intent and not the new one. I don't know how to explain this better. Let's say for my first intent the parameter is "TestOne", after my update, the new intent has parameter "TestX". When the user clicks on the button, on my service I get in intent extras still "TestOne" instead "TestX". So, my guess is that somehow, I need to cancel the previous intent, when the widget button content changes.
Is this the issue ? Am I doing something wrong ? How do I cancel the old intent, I need to recreate it and then cancel it ?
Thank you for your time.
I you keep having this problem even with FLAG_UPDATE_CURRENT, try defining a different requestCode each time, with something like this:
private static int request = 0;
...
PendingIntent pendingIntent = PendingIntent.getService(context, request++, intent, 0);
So each time a new PendingIntent is created, a new requestCode is used, at least during class life.
I hope it helps.
I think you want to set the flag http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT as the last parameter to PendingIntent.getService

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

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?
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.
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.

Categories

Resources