I am just having a hard time understanding the AlarmManager system, tied in with future notifications etc. I can't seem to get the AlarmManager to set alarms at the correct frequency.
I'm also unsure where I should actually create an alarm, and what type is most suited to my needs.
Updates are based on Preferences which will be detailed below.
When my application is launched, the service is called when a FragmentActivity is created. Within the onCreate(), I have the following:
Intent mServiceIntent = new Intent(this, ServiceUpdater.class);
if(startService(mServiceIntent)==null)
startService(mServiceIntent);
Lots of other stuff happens and fragments are shown ect, but this is essentially to ensure the service is running. Note, I also have it set to call the BroadcastReceiver on System startup.
public class ServiceUpdater extends IntentService{
private SharedPreferences defaultPrefs;
private SharedPreferences userPrefs;
private SharedPreferences.Editor editor;
// Alarm Service
private AlarmManager alarmManager;
private PendingIntent alarmIntent;
public ServiceUpdater() {
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
defaultPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
userPrefs = getSharedPreferences("user", Context.MODE_PRIVATE);
long updateFrequency = (Long.parseLong(defaultPrefs.getString("updateFrequencyPref", "24")))*1000*60*60;
// in hours = 1000*60*60*'24'
long thirtySecondsAfterWake = SystemClock.elapsedRealtime() + 30*1000; // 30 seconds after the device boots
Intent intent1 = new Intent(this, UpdateReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, thirtySecondsAfterWake, updateFrequency, alarmIntent);
if(defaultPrefs.getBoolean("updatePref", true))
new Update().execute();
}
private class Update extends AsyncTask<Void, Void, Integer>{
private int newNumber;
@Override
protected Integer doInBackground(Void... params) {
newNumber= new HttpServices().getNewNumber();
return newNumber;
}
@Override
protected void onPostExecute(Integer noJobs){
if(newNumber > 0){ //userPrefs.getInt("oldNumber", 0)){
editor = userPrefs.edit();
editor.putInt("oldNumber", newNumber);
editor.commit();
if(!FragActivity.active)
new MyNotif(getApplicationContext(), "NewData");
}
}
} // end Async
} // end service class
public class UpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent updater = new Intent(context, ServiceUpdater.class);
context.startService(updater);
}
}
My guess is that when the alarm calls the Receiver, it creates a new Alarm, and then updates the old one, setting the next update time to be 30 seconds in the future; which explains why the HTTP request is happening (and I'm getting notifications every 30 seconds or so.
I want to ensure my alarm runs even when the application is not running.
My aim for this application is to do the following.
Where do I correctly set the Alarm so that it is not recreated every time the service is - but runs correctly even when the application isn't running?
Thanks for any help in advance.
but this is essentially to ensure the service is running
I have no idea why you are starting the service twice.
ServiceUpdater.class
I have no idea why you are using an AsyncTask
inside an IntentService
. This is bad on several levels. onHandleIntent()
is already called on a background thread, and I would expect your app to flat-out crash when trying to create an AsyncTask
on a background thread. Just move all the background logic into onHandleIntent()
(or methods called by onHandleIntent()
).
My guess is that when the alarm calls the Receiver, it creates a new Alarm, and then updates the old one, setting the next update time to be 30 seconds in the future; which explains why the HTTP request is happening (and I'm getting notifications every 30 seconds or so.
I have no idea why you are setting up a repeating alarm on every run.
Where do I correctly set the Alarm so that it is not recreated every time the service is - but runs correctly even when the application isn't running?
Your code to set up the AlarmManager
schedule needs to be executed:
On the first run of your app (since you have not had an opportunity to set up the alarms yet)
After the user force-stops your app from Settings (since your previously-scheduled alarms are wiped out)
After a reboot (since your previously-scheduled alarms are wiped out)
A typical pattern for handling the first two is to keep track of when your alarm code last ran, such as in a SharedPreference
. Then, either in a custom Application
or in a likely entry point of your app (e.g., launcher activity), check the SharedPreference
value for your last alarm run time:
If there is no value, that means it's the first run of your app, so you schedule the alarms
If there is a value, and it is significantly longer than your polling period, you assume that your app was force-stopped, and so you schedule the alarms
Otherwise, there is a plausible value, so you assume that your alarms are working just fine
Handling the reboot scenario is a matter of running through your AlarmManager
scheduling logic in response to an ACTION_BOOT_COMPLETED
broadcast.
Note that you are using ELAPSED_REALTIME
, which means that the alarm will be delayed if the device is in sleep mode.
Also note that you are using setInexactRepeating()
, which means that the alarm will go off sometime within the polling period, but not at a precise interval.