Ive been searching for how to using multiple alarms, and did find post in Stackoverflow, but never a straightful answer.
Im trying to set multiple alarms who will call a receiver class (AlarmBcast in my case) and, according to which alarm triggered the call, take different actions.
At this point I followed my way creating diferent receicer classes for each alarm call (and thus a different Intent, each with his own PendintIntent).
I read someone in other thread suggested making a stack (list) of alarms visible, and so using one receiver class for all alarms, but that is not an approach I would like to take.
There is a way to "see" which pendingintent was responsible for the call?.
only the intent is passed, but as there is only one, cant get which call was from it.
Before taking the way of the multiple receivers, this is how my code(pseudo) looked
Setting the alarms...
public class SelectedService extends Service {
//get dates from main
//do some date math
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Intent _myIntent = new Intent(this, AlarmBcast.class);
//setting Alarm A
PendingIntent _myPendingIntent = PendingIntent.getBroadcast(this, 123, _myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, partidocalendar.getTimeInMillis(),_myPendingIntent);
//setting Alarm B
PendingIntent _myPendingIntent2 = PendingIntent.getBroadcast(this, 124, _myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, convopartidocalendar.getTimeInMillis(),_myPendingIntent2);
//setting Alarm C
The receiver as i wa planning it ...
public class AlarmBcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//how to identify call A from B ??
if(AlarmA){}
if(AlarmB){}
}
Maybe i have some conceptual mistake? Back to programming since after 15 years (mostly assembler before)
You can put an "extra" in the Intent that identifies which alarm it is. For example:
_myIntent.putExtra("alarm", "A");
Do this before calling PendingIntent.getBroadcast() for each different alarm.
Then, in your BroadcastReceiver.onReceive() you can check the "extra" in the Intent to determine which alarm got triggered.
I fixed this issue by separating and creating two different Notification Channel and Classes
Related
this is a very dumb question and I still cannot figure out how does AlarmManager work in Android. Suppose I want to schedule a repeating task every half an hour. I want to schedule it at activity onCreate(). I do something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_HALF_HOUR,
AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
}
Now my question is how does OS knows that this alarm has already been scheduled? I mean it is not scheduling a new one every time activity creates, is it? Otherwise, after 10 activity launches I would get alarm every three minutes and not half an hour. Please, any Android guru, explanation about the issue.
Now my question is how does OS knows that this alarm has already been scheduled?
AFAIK, it looks for an existing alarm for an equivalent PendingIntent. Here, by "equivalent PendingIntent", I mean:
the same operation (e.g., getBroadcast())
the same ID (second parameter to getBroadcast())
an equivalent Intent
Here, by "equivalent Intent", I mean that they match on all the routing information, which in your case is the ComponentName generated from this and AlarmReceiver.class. Extras, in particular, do not count for equivalence here.
I am trying to figure this out for a while now.
In my activity I have set an alarm manager to trigger every 2 mins(for testing) and invoke a service via a receiver. The service is suppose to make network calls etc.
My problem is the AlarmManager triggers the first time correctly but never triggers it again. What did I miss?
In my activity I do this -
//Register an alarm manager
//If no alarm is set
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
if(!defaultSharedPref.getBoolean("isAlarmSet",false)){
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
R.string.interval,
pendingIntent);
editor = defaultSharedPref.edit();
editor.putBoolean("isAlarmSet",true);
editor.commit();
}
In my manifest:-
<receiver android:process=":remote" android:name=".receiver.AlarmReceiver" />
<service android:name=".service.AlarmService"/>
My receiver :-
public class AlarmReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AlarmService.class);
startWakefulService(context,i);
}
}
I even tried the "setRepeating" but no luck. It still triggers only once.
Can someone point out where I missed something?
Thanks in advance.
As the interval for your repeating timer you are giving a resource id - R.string.interval. This doesn't make sense, but will compile since it's an integer. If you want your interval as a resource, you'd be better of using an integer resource, but the most crucial change you need is to pass the actual value of the resource rather than the resource id. So for this, use Resources.getInteger or getString.
This should work, however I encourage you not to use a string resource at all:
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
Integer.parseInt(getResources().getString(R.string.interval)),
pendingIntent);`
The reason you aren't seeing any triggered alarms in practice is that resource ids are very large integers, typically in the 0x8000000 range, so you're effectively setting a recurrent alarm with a very very long interval. If you wait for a month or so, the alarm would be triggered. :-)
If you want a more flexible way to schedule jobs, I would recommend this library that abstracts for you the used scheduler: https://github.com/evernote/android-job
In my code the Interval ( third parameter) on setRepeating() method seems not firing every 5 sec .
It keeps increasing in time, it's like the first one or 2 are mostly in time but the others fires like after 40+secs
So what's wrong here?
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent(this, MainActivity2Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE );
am.setRepeating(RTC_WAKEUP,System.currentTimeMillis(),1000*5,pi);
}
}
Take a look here: http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating(int, long, long, android.app.PendingIntent)
As you're firing alarm every 5 seconds:
Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Your code is ok. Explanation of a delay you're experiencing may be:
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
From what I understand from your code you are trying to run MainActivity2Activity.class 5 seconds after the creation of MainActivity.class.
I would advice you to use FLAG_UPDATE_CURRENT instead of FLAG_CANCEL_CURRENT in your pending intent.
The FLAG_CANCEL_CURRENT would retain your first ever pending intent and won't update or create a new one until and unless you cancel the original pending intent first.
Using FLAG_UPDATE_CURRENT will ensure that the pending intent is updated every time MainActivity.class is executed, so that pending intent will be fired exactly after 5 seconds the MainActivity.class is created.
Hope this helps.
Basically you wrote PendingIntent.FLAG_CANCEL_CURRENT instead of PendingIntent.FLAG_ONE_SHOT.
Code for Set Alarm by Alarm Manager
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(ALARM_SERVICE);
Intent i1 = new Intent(this, ReceiveAlarmActivity.class);
i1.putExtra("Key", "Value");
PendingIntent operation = PendingIntent.getActivity(getBaseContext(), 0, i1, PendingIntent.FLAG_ONE_SHOT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Your_Date.getTime(), 5000 operation);
You have to pass Your Date.
Done
I want to make my application set alarms every day at lets say 7 am a list of pills for the user. So far I have been doing it when a user adds a new pill, I will set the alarm directly, but I want to make it set alarms for today only. I am able to get a list of pills for some day using xpath, and getting the pills in a list. Now I was thinking if this is feasible to have some kind of hidden activity that keeps running or something that will set the daily pills. If someone could give me directions as to what I should be looking for to solve this problem, any kind of help would be appreciated.
You should use: Alarm Manager. And place it in Service. Read also about BroadcastReceiver
I will give an idea for this.
Schedule the first Alarm at 7 am using the set method of AlarmManager and register a BroadcastReceiver to be executed at 7 am using the same AlarmManager.
At 7 am your Alarm and BroadcastReceiver will execute. In the onReceive method of your BroadcastReceiver again set the Alarm and BroadcastReceiver so that it becomes a self loop.
pseudo code to set broadcastReceiver class:
Intent intent = new Intent(this, broadcastReceiver.class);
intent.putExtra("subject", subject);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,
0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager am= (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, "Your specific time", pendingIntent);
broadcastReceiver.class:
public class TimeAlarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//set the alarm and broadcast receiver again
}
I have implemented an Alarm class wich should set a new pending Intent and always overriwrite the old one. (I would rather stop/delete all old ones but I dont know how to)
private void startAlarm(){
Intent intent = new Intent(source, Alarm_Activity.class);
// 10000 should be the ID of Intent
PendingIntent pendingIntent = PendingIntent.getActivity(source, 10000, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)source.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),pendingIntent);
}
Unfortionatly I create this class multiple times and from different activities. I think this is the reason why it doesnt cancel the last intent (Flag_cancel_current). How can I make the Flag work throughout multiple instances of this class?
Given your code, so long as all places are using the same Intent (pointing to Alarm_Activity.class) and are using the same PendingIntent ID (10000 in your sample), your code will cancel any current PendingIntent.
This does not cancel any current alarms.
To cancel an alarm, call cancel() on AlarmManager. In particular, if you do this, get rid of PendingIntent.FLAG_CANCEL_CURRENT, so your cancelling of the old PendingIntent does not somehow interfere with your cancelling of the old alarm tied to that PendingIntent.