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
Related
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
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 have created a configure activity for my widget, where the user can choose from various update frequencies.. Until now I started the alarm in the OnEnabled() method, like this:
Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 1000 * 60,
pendingIntent);
The settings are saved in shared preferences with a unique name (widgetId) and in this OnEnabled() method I can't retrieve the settings here because I can't get the widgetId yet.
There's an another problem, the user can change the frequency anytime, but this method is called just once, at the beginning. So I think I need to start the alarm in OnUpdate(), but I don't know how to do it, I don't want to make multiple instances of an alarm accidentally so I would like to ask for some advice.
To answer your second problem, calling setRepeating multiple times will not create multiple alarm as far as you provide same PendingIntent and same request code along with PendingIntent.FLAG_UPDATE_CURRENT flag. I would also suggest to use setInexactRepeating instead of setRepeating. So you can use the same code in OnUpdate() too with new frequency. Go through docs of FLAG_UPDATE_CURRENT and setInexactRepeating for more detials.
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
}
When setting a service to go off at particular time, I use the AlarmManager system service.
Everything goes off without a problem, service is called and actions take place.
When the alarm time is reached, the service starts, and at this point I get the system time (System.currentTimeMillis()). I'm guessing this wont be the actual time the service start. Is there a way to get the time that was set for this PendingIntent?
ie
Set alarm for 9am.
DoStuffService starts at 9am.
DoStuffService knows it was supposed to start at 9am, and uses this value for future functions.
When you create an intent for your alarm, you could put extra data, including time of the alarm, into it like this:
Intent intent = new Intent("action name");
//put extra data into the intent:
intent.putExtra("alarm_time_hours", hours);
intent.putExtra("alarm_time_minutes", minutes);
PendingIntent sender = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
Then in your receiver or service you need to get this extra data from received intent. Use something like this:
Bundle bundle = intent.getExtras();
if(bundle.containsKey("alarm_time_hours")) {
int hours = bundle.getInt("alarm_time_hours");
}
if(bundle.containsKey("alarm_time_minutes")) {
int minutes = bundle.getInt("alarm_time_minutes");
}
Is there a way to get the time that was set for this PendingIntent?
No, sorry.
However, it should not be terribly difficult for you to determine it yourself. Following your example, if your service reports that it is now 09:00:02.36, you should be able to round down to determine that this is the 9am alarm.