Alarm Manager Reliability - android

I've been struggling with this problem for days. I've also checked the documentation and several topics but didn't find any solution / explanation.
I am testing my application on LG p500 but I did a few test on Droid too and I get the same result.
My application uses AlarmHandler to schedule alarm. The application works correctly on the emulator and also on the device until the device has enough free memory.
When I start several other applications on the device and the memory is low the alarm will not fire anymore. As soon as I stop the "other" application the alarm works fine again.
Let me report the test and the result.
I set an alarm on my application 10 minute later.
I start several application (browser, google map, gmail, K9Mail,....)
I start the catlog to see the log of my application
Wait 15 minute without working on the phone
After 10 minutes the alarm should be fired but nothing happen until I wakeup my phone pressing a button
When I wake-up my phone the alarm immediatly fires and all the notificatin happen.
I stop the "other" application I previously started (browser, google map,...)
Set again an alarm 10 minute later
I start the catlog to see the log of my application
Wait without working on the phone
10 minutes later the alarm fires and I get notified.
I did this test several time and I get the same result.
Then I tried to set an alarm using the "Catch" application I previously downloaded from the market and I get the same behaviour so it looks like this is not a problem of my application.
Looking at the log of my application I do not see any error / exception but it looks like that when the system is low on memory something happen and the broadcast receiver does not start until the phone is waked up throught the keyboard. As soon as I wake-up the phone the receiver start and all the notification happen.
Here the code I used:
The Receiver:
public class NotificationReceiver extends BroadcastReceiver
{
public static final String LOG_TAG = "YAAS - Notification Receiver";
#Override
public void onReceive(Context context, Intent intent)
{
ScheduleActivityService.acquireStaticLock(context);
Log.i(LOG_TAG, "Received alarm - id: " + intent.getIntExtra("id", -1));
Intent intent2 = new Intent(context, ScheduleActivityService.class);
intent2.putExtra("id", intent.getIntExtra("id", -1));
context.startService(intent2);
}
}
The Service
public class ScheduleActivityService extends Service
{
public static final String LOCK_NAME_STATIC="it.hp.yaas.AppService.Static";
public static final String LOG_TAG = "YAAS - ActivityService";
private static PowerManager.WakeLock lockStatic = null;
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder
{
public ScheduleActivityService getService()
{
return ScheduleActivityService.this;
}
}
#Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
public static void acquireStaticLock(Context context) {
getLock(context).acquire();
}
synchronized private static PowerManager.WakeLock getLock(Context context)
{
if (lockStatic == null)
{
PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOCK_NAME_STATIC);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
/**
* This method is called when an alarm fires that is its alarm time is reached.
* The system assume that the alarm fired match the alarm time of the first
* activity.
* #param intent intent fired
* #param flag
* #param startId
*/
#Override
public int onStartCommand(Intent intent, int flag, int startId)
{
super.onStartCommand(intent, flag, startId);
try {
Log.i(LOG_TAG, "Alarm fired: " + startId + " - id: " + intent.getIntExtra("id", -1));
AlarmHandler.getInstance().onAlarmFired(intent.getIntExtra("id", -1));
}
finally { getLock(this).release(); }
return START_STICKY;
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.i(LOG_TAG, "Destroy");
}
}
An piece of code from AlarmHandler, the routine called to schedule the alarm:
public synchronized void onAlarmFired(int alarmId)
{
scheduledAlarmId = -1;
Alarm alarmFired = pop();
if (alarmFired == null) return;
Log.i(LOG_TAG, "onAlarmFired (Alarm: " + alarmFired + ") at (time: " + Utilities.convertDate(new Date(), "HH:mm:ss") + ")");
notifyAlarmListener(alarmFired);
if (alarmFired.reschedule(null) != null) add(alarmFired);
Alarm alarm = peek();
if (alarm != null && scheduledAlarmId != alarm.getId()) scheduleEvent(alarm);
}
/**
* Schedule an alarm through AlarmManager that trigger next activity notification
* #param alarm alarm to be scheduled
*/
private void scheduleEvent(Alarm alarm)
{
Log.i(LOG_TAG, "scheduleEvent - (Alarm: " + alarm + ")");
Intent intent = new Intent(context, NotificationReceiver.class);
intent.putExtra("id", alarm.getId());
// In reality, you would want to have a static variable for the request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(context, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, alarm.getTime().getTime(), sender);
scheduledAlarmId = alarm.getId();
}
And finally this is a piece of Manifest file:
<activity android:name=".ListActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".EditActivity"/>
<activity android:name=".SettingsActivity"/>
<service android:name="ScheduleActivityService"
android:label="YAAS Service"/>
<receiver android:name="NotificationReceiver" />

Are you sure your process doesn't get killed when you start all those applications? If it does, the alarms you set will die with it. It's not exactly clear who and when schedules the alarm in your code, but if it's the service, since it's sticky, it will eventually gets re-started, and you will get an alarm at some point (when you wake the device).
An easy way to check what alarms are registered at different points of your testing:
# adb shell dumpsys alarm

My code is very similar to yours on an alarm app that I wrote and use regularly. I haven't been able to reproduce the problem that you describe. I can't seem to get my phone to a state of extremely low memory. I opened every app I have installed and still have 260M free on my HTC Rezound.
As a safeguard in my app I used alarmmanager.setRepeating() instead of .set(). I set the repeat interval to 20 seconds. I passed the alarm ID as an intent extra just as you have. When my service starts it immediately cancels the pending intent using the alarm ID. My logic here is that if for any reason my alarm fails it will continue to try every 20 seconds until it succeeds.

In your code is AlarmManager.set(), which is not guaranteed to fire at the time you specify. It may fire 30 minutes or even 6 hours later, which I've seen happen on devices like the Xiaomi POCO F1.
Instead use AlarmManager.setExact() to schedule your code to run at a specific time.
Android 12 introduces an exact alarms permisison. If you don't want to deal with that, you can instead use AlarmManager.setWindow() with a small window like 15 minutes.

Related

Scheduled alarm never calls receiver class

I'm trying to set an alarm to fire every 5 minutes.
This is the code for setting the alarm :
#Override
public void scheduleAlarmManager() {
Timber.i("After SignIn sets AlarmManager");
// broadcast
Intent intent = new Intent(this, PatientAlarmReceiver.class);
intent.setAction(PATIENT_START_ALARM_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, REQUEST_CODE, intent, 0);
// and set alarmManager
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar currentCal = Calendar.getInstance();
long currentTIme = currentCal.getTimeInMillis();
// if there's not an Alarm already set then set one
if (!isAlarmSet(this)) {
Timber.i("Alarm not set - so set one");
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
currentTIme + TWO_MINS_DURATION, TWO_MINS_DURATION, pendingIntent);
}
}
and I can verify that I set the alarm correctly since I see in my logcat the messages I log with Timber.
My Receiver class is :
public class PatientAlarmReceiver extends BroadcastReceiver {
public static final String TAG = "PATIENT-ALARM-RECEIVER";
public static final String PATIENT_START_ALARM_ACTION = "bp.headsup.receivers.alarm.patient";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Inside OnReceive Patient");
Timber.i("Inside OnReceive Patient");
if (intent == null || intent.getAction() == null) {
return;
}
String action = intent.getAction();
if (PATIENT_START_ALARM_ACTION.equalsIgnoreCase(action)) {
onStartCheckForConnectionRequest(context);
}
}
/**
* If is connected to network starts services
*/
private void onStartCheckForConnectionRequest(Context context) {
NetworkUtils networkUtils = new NetworkUtils(context);
if (networkUtils.isNetworkConnected()) {
Intent checkForConnRequestIntent = new Intent(context, PatientCheckForConnectionRequestService.class);
context.startService(checkForConnRequestIntent);
Timber.i("Starts Service From PatientALARMMANAGER");
}
}
}
And I have declared in Manifest :
<!-- Receivers -->
<receiver
android:name="bp.headsup.receivers.PatientAlarmReceiver" />
Also if I run : adb shell dumpsys alarm
I can see :
ELAPSED_WAKEUP #0: Alarm{42d804e8 type 2 bp.headsup.mock}
operation=PendingIntent{42d0c230: PendingIntentRecord{42d0f000 bp.headsup.mock broadcastIntent}}
Mock in the above response is the sourceSet I'm using - dont know if it has anything to do with this I just mention it.
The problem is I never read in logcat the messages I have in onReceive on my Receiver class, and obviously no service starts. Anyone can help with that ? I'm using a device which runs with kitKat 4.4 (api 19) but I have tried it with an emulator too and the result was the same.
You're setting an ELAPSED_REALTIME alarm, which is based on the time since the last boot. However, you're passing it a starting time based on the "wall clock", so your alarm is actually set quite far in the future.
You can either change the alarm to an RTC type, or get the starting time from SystemClock.elapsedRealtime(). Given your described behavior, keeping the elapsed type and correcting the starting time seems appropriate.

Start service periodically with AlarmManager

According to these examples: here and here, I was trying to create Service which starts periodically.
First I created Service:
public class MonitorService extends IntentService {
private static final String TAG = "MonitorService";
public MonitorService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("TAG", "Service method was fired.");
}
}
Next I created Receiver:
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "MyReceiver on receive");
Intent i = new Intent(context, MonitorService.class);
context.startService(i);
}
}
I added starting method for this in MainActivity:
public void scheduleAlarm() {
Intent intent = new Intent(getApplicationContext(), MyReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
long firstMillis = System.currentTimeMillis();
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// 1s is only for testing
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, 1000, pIntent);
}
which is calling of course in onCreate method.
And I didn't forget to change AndroidManifest:
<receiver
android:name=".MyReceiver"
android:process=":remote" >
</receiver>
<service
android:name=".MonitorService"
android:exported="false" />
And unfortunately the result is that nothing happens in my logs.
So I have two questions.
QUESTION
How to solve issue with not starting service?
If I add scheduleAlarm method to onCreate it will be calling every time I start my application, what is the best way to start this method only for the first time application is started?
EDIT
According to #Lasse hints, I started debugging, and realized that Log.d is not working, when I changed it to Log.i, information from MonitorService was logged.
But... debugging is not stoping on breaking point in MyReceiver, and changing Log.d to Log.i there didn't help. Of course MonitorService is firing, weird thing.
Also time with 1000 ms results in firing service every minute, maybe it's minimum time, and changing to AlarmManager.INTERVAL now doesn't matter.
EDIT 2
Finally I'm getting logs from both service and receiver. I had tried many times and after that it is working, but I don't know why.
But with that another problem has appeared - I'm getting warning when my Service is running
W/art: Suspending all threads took: 21.787ms
I thought that Service is running background so it doesn't matter how long it is, should I concern about this warning?
Edited
Regarding the first question :
See this from the developer website
setInexactRepeating(), you have to use one of the AlarmManager interval constants--in this case, AlarmManager.INTERVAL_DAY.
So change your 1000 to use of of the constans
Regarding your other question you could override the application object and start it there. This way it is only called when launching the app.

Android Service stops automatically

I am making an application with a feature of alarms in it. I am using service for this which keeps checking the current time of device against the times in my DB.
My problem is that this service stops if the app removed from the background or if the device is rebooted. I have used START_STICKY to keep it running in background and used a broadcast receiver to start it on reboot.
The major concern is that whatever I have coded is working on a MOTO G device. Reboot, clearing from background, everything, the service is running fine. But in Xiomi phones and Huawei Honour, It stops once cleared from background or rebooted.
The Service code:
public class RemindService extends Service {
final long delayMillis=500;
Handler h=null;
Runnable r;
SharedPreferences sp;
PendingIntent pendingIntent;
private static final int NOTIFY_ME_ID=1337;
#Override
public void onCreate() {
h=new Handler(Looper.getMainLooper());
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags,int startId) {
r = new Runnable() {
public void run() {
//SOME OF MY IF-ELSE CONDITIONS
Intent myIntent = new Intent(RemindService.this, ReminderPopUp.class);
int randomPIN = (int)(Math.random()*9000)+1000;
pendingIntent = PendingIntent.getActivity(RemindService.this, randomPIN, myIntent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC|AlarmManager.RTC_WAKEUP, System.currentTimeMillis() , pendingIntent);
h.postDelayed(this, delayMillis);
}
};
h.post(r);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
h.removeCallbacks(r);
}
}
My Manifest declarations:
<service
android:name="test.aguai.medieazy.RemindService"
android:enabled="true" />
<intent-filter>
<action android:name="test.aguai.medieazy.START_SERVICE" />
</intent-filter>
Has anybody else faced this problem? I think it is a problem of modified OS, but anyways my app is not working properly. Please Help.
Rather than poll the device database constantly, I would make use of the AlarmManager service as I described in this answer:
Android Polling from a Server periodically
Set up the alarm to fire at the first scheduled time. When it fires, set up the next time and so on. There is no need to set up every alarm at once as only one can ever fire at a time.
When the alarm fires, you can start a service to perform whatever task you need (including the setting of the next alarm)
Try Lik this it will Work
// for Every 6 minutes exact repeating service
Intent myIntent2 = new Intent(sign_in.this,MyAlarmService.class);
pendingintent3 = PendingIntent.getService(sign_in.this, 2,myIntent2, 2);
AlarmManager alarmManager2 = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(System.currentTimeMillis());
calendar2.add(Calendar.SECOND, 30);
alarmManager2.set(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), pendingintent3);
alarmManager2.setRepeating(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), 360 * 1000,pendingintent3);
manifest permission
<!-- Web data Sync Service -->
<service android:name="com.example.MyAlarmService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</service>
If you want your service to be running until explicitly stopped then consider calling startService(), to start the service. This allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().
Remember you must explicitly stop the service, by calling stopSelf() or stopService().

Android Service won't run from AlarmManager

I have a problem with running a service from Alarm manager.
I am building an app that notifies the owner on the namedays of his facebook friends. It all works nicely, but the notification won't show up.
I've set up an AlarmTask that creates the PendingIntent and sets the AlarmManager, like this:
public void run() {
// Request to start are service when the alarm date is upon us
Intent intent = new Intent(context, NotifyService.class);
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
intent.putExtra("notifyID", ID);
PendingIntent pendingIntent = PendingIntent.getService(context, ID, intent, 0);
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), pendingIntent);
}
The ID is specific for every nameday.
Now in my NotifyService, I have set up these:
#Override
public void onCreate() {
super.onCreate();
System.out.println("NOTIFICATION SERVICE onCreate()");
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
System.out.println("INTENT RECIEVED: " + intent + " " + flags + " " + startId);
// If this service was started by out AlarmTask intent then we want to show our notification
if(intent.getBooleanExtra(INTENT_NOTIFY, false)){
int ID = intent.getIntExtra("notifyID", -1);
showNotification(ID);
}
// We don't care if this service is stopped as we have already delivered our notification
return START_STICKY;
}
Both the methods are executed once when I start the app, but when the notification should come up, nothing happens.
Is there a way to test if the AlarmManager really executes the PendingIntent?
Should I rather use IntentService? Why/how?
Thanks a lot.
I tried to change it to BroadcastReciever, looking like this:
public class NotificationBroadcastReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("BROADCAST RECIEVED");
}
}
The AlarmTask bit is changed to this:
Intent intent = new Intent("NotificationBroadcast");
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
intent.putExtra("notifyID", ID);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), ID, intent, 0);
System.out.println("date for notification: " + date.get(Calendar.DAY_OF_MONTH) + "." + date.get(Calendar.MONTH) + "." + date.get(Calendar.YEAR));
System.out.println("epoch time in milils: " + date.getTimeInMillis());
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), pendingIntent);
and relevant manifest part looks like this:
<receiver
android:name="cz.cvut.kubispe2.jmeniny.NotificationBroadcastReciever"
android:exported="false">
<intent-filter>
<action android:name="NotificationBroadcast" />
</intent-filter>
</receiver>
I checked if the date that is to be set is equal to the epoch time and it is, but still, the onRecieve method is never called.
Both the methods are executed once when I start the app, but when the notification should come up, nothing happens.
_WAKEUP alarms are only guaranteed to wake up the device if they route to a BroadcastReceiver, not a Service. So long as what you are doing is very short (1-2 milliseconds), you can safely do that work in onReceive() of a BroadcastReceiver. The work you are presently doing in your Service would qualify.
Beyond that, use adb shell dumpsys alarm to confirm that your alarm is scheduled for when you think it is.
Should I rather use IntentService?
It would certainly be a better option than a regular Service, which you are leaking in your current implementation. However, the _WAKEUP limitation still holds, which is why I wrote WakefulIntentService, to help bridge the gap. Again, though, with the current limited work you are doing, just using a BroadcastReceiver should suffice.
try using application context.
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(), ID, intent, 0);
And work with android logs. Then you will see if it's running in your console
Seems like I finally resolved it, I used the broadcast reciever, and found out where the error was - Calendar takes the month argument from 0 to 11, instead of 1-12, which I thought, since all the other arguments are dealt with normally. So I was just putting up a notification for the end of May, instead of today, when testing.
Anyway, thank you all for help, it was very appreciated.

Android: How to periodically send location to a server

I am running a Web service that allows users to record their trips (kind of like Google's MyTracks) as part of a larger app. The thing is that it is easy to pass data, including coords and other items, to the server when a user starts a trip or ends it. Being a newbie, I am not sure how to set up a background service that sends the location updates once every (pre-determined) period (min 3 minutes, max 1 hr) until the user flags the end of the trip, or until a preset amount of time elapses.
Once the trip is started from the phone, the server responds with a polling period for the phone to use as the interval between updates. This part works, in that I can display the response on the phone, and my server registers the user's action. Similarly, the trip is closed server-side upon the close trip request.
However, when I tried starting a periodic tracking method from inside the StartTrack Activity, using requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) where minTime is the poll period from the server, it just did not work, and I'm not getting any errors. So it means I'm clueless at this point, never having used Android before.
I have seen many posts here on using background services with handlers, pending intents, and other things to do similar stuff, but I really don't understand how to do it. I would like the user to do other stuff on the phone while the updates are going on, so if you guys could point me to a tutorial that shows how to actually write background services (maybe these run as separate classes?) or other ways of doing this, that would be great.
I recently wrote one of these and decided it is not a good idea to leave a background service running. It will probably be shut down by the operating system anyway, or it could be. What I did was use a filter for the boot intent and then set an alarm using the alarm manager so that my app was restarted at regular intervals, and then it sent the data. You can find good info on services and the alarm manager in the Android documentation.
First I created a broadcast receiver that simply starts my service when an internet connection is opened (I'm only interested if there is a connection - you might want to filter for the boot event as well). The launch receiver must be short-lived, so just start your service:
public class LaunchReceiver extends BroadcastReceiver {
public static final String ACTION_PULSE_SERVER_ALARM =
"com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM";
#Override
public void onReceive(Context context, Intent intent) {
AppGlobal.logDebug("OnReceive for " + intent.getAction());
AppGlobal.logDebug(intent.getExtras().toString());
Intent serviceIntent = new Intent(AppGlobal.getContext(),
MonitorService.class);
AppGlobal.getContext().startService(serviceIntent);
}
}
In the manifest I have:
<receiver
android:name="LaunchReceiver"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<intent-filter>
<action android:name="com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM" />
</intent-filter>
</receiver>
Notice how I have a filter for my own alarm, which is what allows me to shut the service and have it restarted after it's done its work.
The top of my monitor service looks like:
public class MonitorService extends Service {
private LoggerLoadTask mTask;
private String mPulseUrl;
private HomeBoySettings settings;
private DataFile dataFile;
private AlarmManager alarms;
private PendingIntent alarmIntent;
private ConnectivityManager cnnxManager;
#Override
public void onCreate() {
super.onCreate();
cnnxManager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentOnAlarm = new Intent(
LaunchReceiver.ACTION_PULSE_SERVER_ALARM);
alarmIntent = PendingIntent.getBroadcast(this, 0, intentOnAlarm, 0);
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// reload our data
if (mPulseUrl == null) {
mPulseUrl = getString(R.string.urlPulse);
}
AppGlobal.logDebug("Monitor service OnStart.");
executeLogger();
}
executeLogger starts an asyncTask, which is probably me being excessively cautious (this was only my third Android app). The asyncTask grabs the GPS data, sends it to the internet and finally sets the next alarm:
private void executeLogger() {
if (mTask != null
&& mTask.getStatus() != LoggerLoadTask.Status.FINISHED) {
return;
}
mTask = (LoggerLoadTask) new LoggerLoadTask().execute();
}
private class LoggerLoadTask extends AsyncTask<Void, Void, Void> {
// TODO: create two base service urls, one for debugging and one for live.
#Override
protected Void doInBackground(Void... arg0) {
try {
// if we have no data connection, no point in proceeding.
NetworkInfo ni = cnnxManager.getActiveNetworkInfo();
if (ni == null || !ni.isAvailable() || !ni.isConnected()) {
AppGlobal
.logWarning("No usable network. Skipping pulse action.");
return null;
}
// / grab and log data
} catch (Exception e) {
AppGlobal.logError(
"Unknown error in background pulse task. Error: '%s'.",
e, e.getMessage());
} finally {
// always set the next wakeup alarm.
int interval;
if (settings == null
|| settings.getPulseIntervalSeconds() == -1) {
interval = Integer
.parseInt(getString(R.string.pulseIntervalSeconds));
} else {
interval = settings.getPulseIntervalSeconds();
}
long timeToAlarm = SystemClock.elapsedRealtime() + interval
* 1000;
alarms.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeToAlarm,
alarmIntent);
}
return null;
}
}
I notice that I am not calling stopSelf() after setting the alarm, so my service will sit around doing nothing unless shut down by the op sys. Since I am the only user of this app, that doesn't matter but for a public app, the idea is you set the alarm for the next interval then stopSelf to close down.
Update See the comment from #juozas about using 'alarms.setRepeating()'.
You need to create a separate class that is a subclass of the Service class.
Service Documentation
Your primary application should can call startService and stopService to start up the background process. Theres also some other useful calls in the context class to manage the service:
Context Documentation
I agree with Rob Kent, and in additional I think could be beter to extends WakefulBroadcastReceiver in your BroadcastReceiver and use it's static method startWakefulService(android.content.Context context,android.content.Intent intent), because it garanted your service will not shut by os.
public class YourReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, YourService.class);
startWakefulService(context, service);
}
}
Official documentation

Categories

Resources