Create new Pending Intent every time in Android - android

How do I create a pending intent everytime? Currently my existing pending intent is getting replaced with a new one. I tried using FLAG_ONE_SHOT as well as CANCEL_CURRENT but it didn't work.

add a random number to the request code like that:
Intent intent = new Intent(context, YourClassname.class);
intent.putExtra("some data", "txt"); // for extra data if needed..
Random generator = new Random();
PendingIntent i=PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT);

FLAG_CANCEL_CURRENT- if the described PendingIntent already exists, the current one is canceled before generating a new one.
FLAG_NO_CREATE - if the described PendingIntent does not already exist, then simply return null instead of creating it.
FLAG_ONE_SHOT - this PendingIntent can only be used once.
FLAG_UPDATE_CURRENT- if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent.
If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).

Related

Can PendingIntent.FLAG_IMMUTABLE replace PendingIntent.FLAG_UPDATE_CURRENT?

I'm dealing with PendingIntent with notification.
In my project, I've been using PendingIntent.FLAG_UPDATE_CURRENT in some of code. and the definition of it is below.
Flag indicating that if the described PendingIntent already exists,
then keep it but replace its extra data with what is in this new
Intent. For use with getActivity(Context, int, Intent, int),
getBroadcast(Context, int, Intent, int), and getService(Context, int,
Intent, int).
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.
FLAG_UPDATE_CURRENT still works even if FLAG_IMMUTABLE is set - the
creator of the PendingIntent can always update the PendingIntent
itself. The IMMUTABLE flag only limits the ability to alter the
semantics of the intent that is sent by send() by the invoker of
send().
But I have to choose between FLAG_IMMUTABLE or FLAG_MUTABLE because of Android12. In my case, i don't need to use PendingIntent.FLAG_MUTABLE. the definition of it is below.
Flag indicating that the created PendingIntent should be immutable.
This means that the additional intent argument passed to the send
methods to fill in unpopulated properties of this intent will be
ignored.
FLAG_IMMUTABLE only limits the ability to alter the semantics of the
intent that is sent by send() by the invoker of send(). The creator of
the PendingIntent can always update the PendingIntent itself via
FLAG_UPDATE_CURRENT.
as you can see, they say "FLAG_UPDATE_CURRENT still works even if FLAG_IMMUTABLE is set..." and "The creator of the PendingIntent can always update the PendingIntent itself via FLAG_UPDATE_CURRENT."
So, what i want to know is that FLAG_IMMUTABLE can perfectly replace FLAG_UPDATE_CURRENT in any Android version?
For example
PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
=> PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);
FLAG_IMMUTABLE and FLAT_MUTABLE controls if other apps can modify your PendingIntent. For instance, if you were using a direct reply action in a notification, the system would need you to use FLAT_MUTABLE to allow it to fill in the text the user typed and send it to you.
FLAG_UPDATE_CURRENT is the ability for your app to update its own PendingIntent. This means if you create the same PendingIntent where the only difference is the extras attached to your Intent, FLAG_UPDATE_CURRENT would ensure that your new extras are actually used (instead of just the original set being used again).
So in every case where you were using FLAG_UPDATE_CURRENT, you'd want to continue to use FLAG_UPDATE_CURRENT, adding in the correct mutability flag for your case (which, in 99% of cases, is FLAG_IMMUTABLE).
To apply both flags, use the | symbol in Java (or the word or in Kotlin):
PendingIntent.getActivity(context, requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

How to update/remove old alarms?

I have a functionality in my app that creates alarm when it get data from the external API. when API data is refreshed, it again create alarms based on new data. Every time the user visit that specific view, the current data is pulled from the server and alarm is created. How can I ensure that the alarms created using old data get removed? The functionality is a kind of reminder service.
You can either use the same requestCode you used initially when creating the PendingIntent for your alarms if you used the PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_CANCEL_CURRENT to create additional alarms and it will cancel the alarm first and create a new one in the case of PendingIntent.FLAG_CANCEL_CURRENT or it will update the existing one with the new data in the case of PendingIntent.FLAG_UPDATE_CURRENT
From the Docs
FLAG_CANCEL_CURRENT
Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one. For use with getActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int).
You can use this to retrieve a new PendingIntent when you are only changing the extra data in the Intent; by canceling the previous pending intent, this ensures that only entities given the new data will be able to launch it. If this assurance is not an issue, consider FLAG_UPDATE_CURRENT.
FLAG_UPDATE_CURRENT
Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent. For use with getActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int).
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.
Otherwise, you can cancel them yourself manually if those flags weren't specified. You just need the request code
PendingIntent pendingIntent =
PendingIntent.getBroadcast(mContext, requestCode, alarmReceiverClassIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) mContext.getSystemService(ALARM_SERVICE);
if (am != null) {
am.cancel(pendingIntent);
}

Multiple Pending Intents?

My activity creates a couple of notifications.
Here's how I'm currently doing it, on different resultIntents:
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
context,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
Now, since a flag is compulsory, I'm forced to select from the four flags. What do I do if I want all of them to work independently, and the newer notification isn't affected by the previous one.
A solution was found here: here.
You've to use setAction on the intent to a unique value so that there will be no matching PendingIntents
Here's what I used:
setAction(Long.toString(System.currentTimeMillis()))
From the official documentation
If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).
Intent.filterEquals documentation:
Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.
If you need an unlimited amount of PendingIntents, I would recommend using Intent.setData to some sort of unique value. If you can group them, use setType or addCategory to reduce the number of unique PendingIntents needed.

What's "requestCode" used for on PendingIntent?

Background:
I'm using PendingIntent for alarms via AlarmManager.
The problem:
At first I thought that in order to cancel previous ones, I must provide the exact requestCode that I've used before to start the alarm.
But then I've found out I was wrong, as the cancellation API says:
Remove any alarms with a matching Intent. Any alarm, of any type,
whose Intent matches this one (as defined by filterEquals(Intent)),
will be canceled.
looking at "filterEquals", the documentation says:
Determine if two intents are the same for the purposes of intent
resolution (filtering). That is, if their action, data, type, class,
and categories are the same. This does not compare any extra data
included in the intents.
so I don't get what the "requestCode" is for...
The question:
What is "requestCode" used for?
What if I create multiple alarms with the same "requestCode" ? do they override each other?
requestCode is used to retrieve the same pending intent instance later on (for cancelling, etc).
Yes, my guess is the alarms will override each other. I would keep the request codes unique.
I just want to add to #Minhaj Arfin answer
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
example:
Intent startIntent1 = new Intent(context, AlarmReceiverFirst.class);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, startIntent1, 0);
Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, 0);
From above example, they will not override each other because the receiver is different(AlarmReceiverFirst and AlarmReceiverSecond)
Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, 0);
Intent startIntent3 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent3 = PendingIntent.getBroadcast(context, 0, startIntent3, 0);
From above example, they will override each other, because the receiver is same(AlarmReceiverSecond)
Actually, the documentation clearly states what the request code is used for:
If you truly need multiple distinct PendingIntent objects active at
the same time (such as to use as two notifications that are both shown
at the same time), then you will need to ensure there is something
that is different about them to associate them with different
PendingIntents. This may be any of the Intent attributes considered by
Intent#filterEquals(Intent), or different request code integers
supplied to getActivity(Context, int, Intent, int),
getActivities(Context, int, Intent[], int), getBroadcast(Context, int,
Intent, int), or getService(Context, int, Intent, int).
Since it seems that it still isn't that clear, let me try to explain:
When you want to use a PendingIntent object, you don't just instantiate one. Rather, you obtain one from the system using the PendingIntent static methods (getActivity, getBroadcast, getService etc). The system keeps a bunch of PendingIntent instances and gives you one. Which one it gives you, it depends on the input parameters you pass to these getter methods. Those input parameters are: Context, i.e. the target receiver of the intent, the Intent to use, requestCode and flags. When you pass the same Context, the same requestCode and the same Intent (meaning an intent that filterEquals with another intent), you get the same PendingIntent object. The point is that the system wants to have as few PendingIntent objects as possible, so it tends to reuse the existing ones, as much as possible.
For example, you have two calendar notifications, for two different dates. When you click on one of them, you want your app to open to the corresponding date of that notification. In that scenario, you have the same Context target, and the Intent object you are passing differ only in the EXTRA_DATA (which specifies the date that should be open). If you provide the same requestCode when obtaining the PendingIntent object, then you will end up with the same PendingIntent object. So, when creating the second notification, you will replace the old Intent object with the new EXTRA_DATA, and end up with two notifications pointing to the same date.
If you want to have two different PendingIntent objects, as you should in this scenario, you should specify a different requestCode when obtaining the PendingIntent object.
in my case i want to open the same activity with two different intents so if two or more FCMS are there in the tray, any one of them will only open other will not, so i changed the requests codes of pending intent then it worked.
PendingIntent pendingIntent =
PendingIntent.getActivity(this, **Some unique id for all GCMS** /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
one important thing about requestCode that will seriously trouble your app is when using widgets.
widgets will not work after phone reboot if their requestCode are the same.
that means the pendingIndent you set on the remoteViews of your widget must be set unique requestCode, usually the widgetId accompanying a number.

How to use requestCode in PendingIntents

I'm trying to implement a reminder app.I have all reminder details stored in sqlite database such id,title,dateInfo,timeInfo etc.
I want to notify the user at appropriate time about the reminder for which i would be using AlarmManager.
Is the below given steps feasible.
Providing id of row as requestCode in pendentingIntents.
Then setting an alarm that would call a service once triggered.
The service would use this id to get data from the database.
If this is feasible can anyone pls provide me with a code snippet.
Any help would be highly appreciated
You can simply put your rowId as extra in the called intent. Here's a code snippet that might help:
Intent i = new Intent(this, YourServiceOrActivity.class);
i.putExtra("rowId", rowId);
PendingIntent pi = PendingIntent.getActivity(this, 123123, i, 0); //Notice the random requestCode '123123' as it doesn't matter, yet.
And you can set the alarm as follows:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, AlarmManager.INTERVAL_DAY, pi);
//Set the alarm to wake up the device after one day calling the pending intent 'pi'.
Finally you can get the rowId from the intent (onCreate() for example if intent is an Activity) when called as follows:
Bundle extras = getIntent().getExtras();
if (extras != null) rowId = extras.getInt("rowId", 0); //Be safe
Hope this helps.
As others mentioned I would put rowId as an extra, BUT do not be mistaken - as wroten in PendingIntent doc, intents are distinct as below:
If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent. filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).
So if you put your request with the same id for all intents for the same row, with different data, you can get lost with obsolete/repeated data issues.
According to the docs on PendingIntent, the requestCode of the getService(...) method is not used. It's not clear to me what happens to it, so I wouldn't rely on it in any way.
Just pass the row ID as an extra in the Intent.

Categories

Resources