I am trying to cancel an alarm that was set last time my app was run. This alarm has a PendingIntent that was set with PendingIntent.getBroadcast and an inner Intent that contains some variables set by intent.putExtra. My question is this, I know that alarms can be canceled by calling alarmManager.cancel(pendingIntent) where pendingIntent is the same as the one used to set the alarm. But, if the variables placed into the intent are changed will the alarm still be canceled? For example, I set an alarm with intent.putExtra("Joe") where Joe is a contact name. Later my app is closed and when it is re-run I try and cancel the alarm for "Joe" but the user has changed the name of the contact to "Jones". Can I cancel the alarm without knowing the variables I put into the intent?
Thanks!
I think it should cancel the alaram anyway, even though some data is different. The cancel method says:
Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.
And filterEquals 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.
Anyhow, I'd still test it myself.
According to this question (which references the documentation), anything you add using putExtra is not taken into account when checking if an intent is equal to another one.
It shouldn't matter if the extra data is changed.
Related
Is it possible to create two PendingIntents with the same ID ( let's say 889) and the same intent (but different bundle) and then when I cancel PendingIntent with ID 889 will it cancel it both ?
As far as i know, you cant do that.
The System uses the ID to identify the Intents. So if you get a result you never know which of your Intents being processed.
You have to use different IDs if you want to set a repeating alarm for 2 different days. Because if you'll use the same id for each then the notification you set the latest will override the previous one and hence you'll have lose one notification.
I'm fairly new to Android, so please forgive my naiveté.
The app I am working on needs to wake up every hour and do some background data collection. I'm using AlarmManager to set a repeating alarm that starts the service.
I'm currently setting up the alarm in the MainActivity in the onCreate method. My concern is that if the app is closed and reopened and the onCreate method is called again, it would duplicate the alarms. Am I incorrect in assuming this?
One way I'm thinking about circumventing this to use a boolean in SharedPreferences. Is there a more standard way of approaching this issue?
Thank you!
You can set alarm once avoiding duplicates without any problem.
You can statically set broadcast receiver once the OS finishes booting. Register pending intent via PendingIntent.getService() and configure the AlarmManager in the receiver's onReceive() method.
Please note also that every method PendingIntent.getBroadcast(), PendingIntent.getService(), PendingIntent.getActivity() or PendingIntent.getActivities() has flags parameter. You can request your PendingIntent with PendingIntent.FLAG_NO_CREATE flag set. This means that if the system has identical PendingIntent registered then the null is returned. Otherwise new PendingIntent instance is created. Thus, you can rely on this flag to check if your alarm is already set.
Read more about PendingIntent in my response to the similar problem, please(Usage of PendingIntent.cancel() and AlarmManager.cancel()).
Basically, you can still rely on setting your alarm in launching activity by checking first whether you have PendingIntent registered thanks to the PendingIntent.FLAG_NO_CREATE set.
Hope you now understand how to do it.
In onCreate I would probably just cancel all alarms, then set a new alarm. Psuedo code would be something like
Create pending intent for your alarm
call AlarmManager.cancel with that pending intent http://developer.android.com/reference/android/app/AlarmManager.html#cancel%28android.app.PendingIntent%29
set your alarm with the same pending intent.
I have a Service that first creates a new Intent, and calls setAction('foo') on it. After this I call putExtra("key","value123"). Then I call PendingIntent.getService(this,999,intent,0) (no flags passed), and pass the pending intent to the AlarmManager.
But then before the alarm fires (or even after, it seems) I create another Intent and again call setAction('foo') on it, but don't set any extras.
Then I again pass it to PendingIntent.getService(this,999,intent,0). However, this time I call send() on the PendingIntent so as to receive the intent immediately.
What I observe is that the original extras are delivered with the new Intent. I appear to be able to do this over and over, and even if my app is killed, when I restart it, the extras are still there.
However, I don't see anything specifically in the documentation which says whether or not this is actually expected behavior. Is this a reliable method by which I can persist a small amount of data in RAM (only!) in case my app gets terminated? Currently I'm using file on a RAMdisk, but some devices apparently don't have such a thing.
This is the way PendingIntent works ;-)
The first call to PendingIntent.getService() creates a new PendingIntent with the requestCode set to 999 and the Intent set to ACTION="foo".
The second call to PendingIntent.getService) doesn't create a new PendingIntent. It just returns a token (reference) to the first PendingIntent. When you call send() on it, the original PendingIntent is sent.
The reason is that when you call PendingIntent.getService(), Android first tries to find a PendingIntent that matches the one you've specified. To determine if the Intent matches, it checks the ACTION, COMPONENT, DATA and it also checks for matching requestCode arguments. In your case, both calls to PendingIntent.getService() have the same requestCode and the Intents have the same ACTION. NOTE: "extras" in the Intent are not considered when determining if the Intents match.
If you always want to (re)use a single PendingIntent and just override the "extras" every time you use it, you can add the flag PendingIntent.FLAG_UPDATE_CURRENT to the call to PendingIntent.getService().
If you need to create several PendingIntents in parallel, with different "extras", you need to make sure to use a unique requestCode every time you call PendingIntent.getService().
I register a broadcastreceiver in AndroidMainfest.xml
And in my app, a function is that User can set a time and at this time the app will send a notification. I get the arguments User set ,and use alarmManager to set a task which will happened at the time user set.
But I find that GOOGLE API said that:
If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by filterEquals(Intent)), then it will be removed and replaced by this one.
So if I want set two or more task,the Intent will be replaced , and at end I can only get one notification,it's not the result I want.
And then I found the intent was identified by action, data, type, class, and categories,
but I can't change action(the intent's action is the intent-filter's action was registred in the AndroidMainfest.xml ),but at the time that I change the other arguments I can't even receive a broadcast.
I thought there are four ways to solve this problem,but I only made one..
create lots of broadcastreceiver and register these in
AndroidMainfest.xml,and in this way I could change the intent's
action
register the broadcastreceiver in the program ,but I didn't
make it
use service + Timer class ..
To make two intent different without change action.
Any help will be appreciated!!
Intent intent = new Intent("aaa"); //there was a broadcastreceiver's intent-filter "aaa"
intent.putExtra("title", title);
intent.putExtra("table", "计划");
PendingIntent pi = PendingIntent.getBroadcast(Alarm.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(Alarm.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+time, pi);
The code is in onClickListener{onClick(){}}
Instead of Broadcasting which is not letting you to set repeat alarm you can use the calendar Object and set the alarm at whatever desired time. Once the alarm gets ON, your code will run automatically and as many times you have set the alarm.
You can also take a help of the following tutorial. I am sure it will help you out somehow.
http://blog.mikesir87.io/2013/04/android-creating-an-alarm-with-alarmmanager/
I am scheduling multiple intents to be send to a BroadcastReceiver.
The difference between every intent is the time when it will be received and extra data it contains.
Now I need to allow user to cancel specific alarms. According to AlarmManager.cancel() javadoc, it compares intents using filterEquals method:
http://developer.android.com/reference/android/content/Intent.html#filterEquals(android.content.Intent)
Now the problem is that according to filterEquals, all my intents are the same. Method checks against "action, data, type, class, and categories".
And unique data is either in intent extra bundle or as a time in AlarmManager.
I tried changing any of these parameters - for example using:
intent.setData(Uri.withAppendedPath(Uri.EMPTY, "some_unique_data"));
That would make every intent unique according to filterEquals method, but after changing Data to something like this, my intent does not reach BroadcastReceiver anymore.
What specific bit of data can I change to make every intent unique according to filterEquals and still receivable to my simple BroadcastReceiver?
Maybe I can modify my receiver in any way?
Ok, so I figured it out. As my every alarm has unique time and object ID, this is how I create my PendingIntent:
return PendingIntent.getBroadcast(context, time*100000+o.getId(), toFire, 0);
Now time is either 24 or 15 (24 hours before or 15 minutes before event I fire my alarm) and alarm data object contains unique ID. So I add both and specify it as a "requestCode" parameter in getBroadcast. That is enough to make unique intents based on same data.
Hope this helps anyone who has the same problem!
I ran across a similar problem for my app.
In my app, I used the SQLite DB to store details about each alarm, along with a unique ROW_ID.
So in my alarm listview, each row had a corresponding ROW_ID associated with it.
If the user clicks on a particular row, I just pass this ROW_ID to the method that performs the delete operation
Now, all my alarms were created with Intents which had their data part set as:
Uri.parse(Constants.INTENT_PRE + ROW_ID);
so in order to delete them, I create an Intent that has same data (as above, along with the unique ROW_ID) that was used while creating it.
Needless to say, from "action, data, type, class, and categories", only the "data" part is different for each of my existing PendingIntents.
Hope this helps!