Keeping a GPS service alive and optimizing battery life - android

I must build an application with a GPS tracker running during about a day. I'm aware of similar questions in SO but I haven't found any answers to some questions I have.
-I need a GPS fix every 10 min, so I think the best way to do it is to start the location service, get a fix (or timeout) and stop the service (with removeUpdates()). How can I have an application (or service or whatever) running this cycle every 10min and be sure it will continue as long as there is some battery left (even if device goes to sleep, it should wake it up every 10min to get a fix)? Is using AlarmManager a good idea?
-Can I expect the battery to last one day with this method?
I've checked mytracks but the gps listener seems always on and the battery is expected to last no more than 5h.
I've also checked CWAC Location Poller but it does only removeUpdates() on timeout and restart the listener immediately. It also uses a wakelock while in my case I think an AlarmManager could be a better idea.
Any help/suggestion welcome

You are spot on with alarm manager I use
Intent serviceIntent = new Intent(this, TrackerService.class);
mPendingIntent = PendingIntent.getService(this, 0, serviceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(mPendingIntent);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, mPendingIntent);
in a similar app for getting network location
interval is ms between starting the service
the service starts up, gets the location and closes
this was MUCH more battery efficient that hanging around with an active service waiting for reports
that code i posted cancels the previous alarms first so you don't get more than 1 :)

You can check out Passive Receiver
It'll give you an location update whenever another the devices location gets updated - only works on 2.2 or later

Related

How to debug an AlarmManager-activated service

I am implementing a widget that checks on-line train departure times between every minute and every hour, depending on the time of day.
Calling the service with
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() - 10000, 60000, pendingIntent)
works fine, but for debugging I would like to reduce the interval to about 10 seconds which cannot be done because of the 1-minute limit in more recent versions of Android. Clearly, I don't care about battery life in the emulator.
As far as I understand, using an Hander/Timer is not an option, because it required the task to be in the foreground. Is a visible widget "in the forground"?
What is the recommended practice in this case?
you actually have to tasks
configure the alarmmanager to add/remove trigger events via intents
interprete the events with intents in a service
If you seperate both you can easily create a very simple gui/activity that does the same as the alarmmanager would do when being triggerd and that you can debug:
* onSendButtonClick: create and send pendingIntent
for the alarmmanager-handling i would implement logging into a text file each time alarmmanager is added/removed/triggered.
Be prepared that newer android versions may postpone alarmmanager events to save energy until the device is already active and that intervals less than 15 minutes may not work.
you may also need on_boot_complete to reconfigure alarmmanager after device-shutdown

Why is AlarmManager alarm delayed on first run?

Recently, in my timer app, running the timer for the first time causes it to fire an alarm approximately two or three seconds after it should. The strange this is, it only does this the first time I run the timer after installing the app via Android Studio. Every time after that, it runs as expected and the timer goes off after the expected time.
Here is the relevant code:
if(LOG) Log.v(TAG,"Starting the timer service: "+ TimerUtils.time2humanStr(context, mTime));
Intent intent = new Intent( this, TimerReceiver.class);
mPendingIntent = PendingIntent.getBroadcast( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + mTime, mPendingIntent);
The variable mTime is set properly each time, according to the logcat output:
Starting the timer service: 5 seconds
And it works fine every time after the initial run. It was working fine before; could it be a problem with Android or Android Studio? Or am I needing to initialize something? I know I can't expect precise answers without dumping all my code here, I'm just looking for hints (speculation?) as to why this behaviour might be occurring.
Are you using API 19? Check out this note in the documentation:
Note: Beginning in API 19, the trigger time passed to this method is
treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later. The OS will use
this policy in order to "batch" alarms together across the entire
system, minimizing the number of times the device needs to "wake up"
and minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
Source: AlarmManager

onGpsStatusChanged alternatives?

Posted question recently about why my onGpsStatusChanged is called only once and not called anymore, got no answers so will assume solution is unknown (been trying it out for 2 days), so is there perhaps any alternative solution to detect if GPS signal was lost and no location updates are available?
I am running LocationListener in background service.
I need to detect when user lost GPS -> Start alarmManager for 5 minutes and if GPS appears online again -> cancel alarm.
The only problem I have detecting if gps was lost or not.
Loosing GPS just means that you will receive no more location updates.
So why not just setting the Alarm again with each location update you receive.
The set-Methods of the AlarmManager are automatically cancelling Alarms previously set with the same PendingIntent. So you will have only one Alarm set all the time. As soon as no new location is received for longer than 5 minutes your Alarm will be executed.
May be setting the Alarm again every second is too expensive (I have no idea about that). In this case, add a counter, that resets the AlarmManager only every n-th location update. The idea is still the same.

Android does not execute everything on night

I made a program that creates a Service.
The service connects to a website every 5 minutes, collects one line of data and outputs it to a file.
My problem is that it didn't collect the data every 5 minutes. The data was collected once in around 50-70min. Why? Is there something in android that prevents background services from running properly during nights? What is also strange to me, the 50-70 minute breaks happened only when I was not using my phone.
Times it collected the data:
1:40
1:45
1:50
1:55
2:00
2:05
2:10
2:15
2:20
2:25
2:30 I was awake until this.
3:20
4:15
5:00
6:05
6:55
7:55
8:45
10:20
10:50 Woke up at here.
10:55
Your results are not surprising. Android was designed to swipe out (and back in) processes based overall level of resource as well as other factors.
Modifying your service to become a foreground service will certainly improve your results:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
Foreground services are basically services guaranteed by Android to be less susceptible to swipe out,
which is what you want.
But even a foreground service will halt its processing when the devices goes to sleep. And, if you feel your polling logic is important enough so to keep the device from sleeping, you should also acquire a wakelock.
Note: Long running wakelocks have a huge impact of on battery usage. Handle with care!
Finally, please consider using an alarm for your task. Alarms are usually considered better option for
long running polling tasks.
Depending of an approach you use to schedule your updates, the OS might shift updates to decrease battery drain and overall burden. Delayed tasks might be postponed if the device falls into deep sleep (happens at night mostly as the device is inactive during long periods of time).
It's done this way to prevent your battery to be drained to fast. If you really want to wake your device every 5 minutes, you can check the answer to this post and use the AlarmManager

Sleeping service with contentobserver

I've created a service (S) which hosts a ContentObserver (C).
C keeps track of some data and logs changes made to a database (D).
S also has a timer which dumps the content of D to a file on timed intervals.
I have my service running on my phone and all seems fine for a while (a couple of hours or so). Then suddenly it stops recording changes made to the data and stops dumping to a file.
I tried changing the data (provoking onChange on C) and browsing around in the phone to keep the device awake but nothing happened - service stil inactive.
S is still running and when I connect to my laptop I see no errors in the log.
My guess is that the service is sleeping (gets no CPU slice). I've read a bit about a wakelock but I don't want to force the phone to be awake all the time. ().
An alternative is to create a repeated alarm which carry out the work of C every T minutes (polling).
I like the idea with ContentObservers more because the user can alter (especially delete) data between the updates. With a ContentObserver I will get ALL changes, not just snapshots in timed intervals.
Any ideas on how I can wake my service on a regularbasis?
Best regards
Frederik
You can use the AlarmManager to broadcast a pending intent at a set interval. If you use the RTC_WAKEUP type, it will even get sent if the device is asleep.
Intent intent = new Intent("android.intent.action.DO_SOMETHING");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Service.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60*60*1000, pendingIntent);
Then simply register a broadcast receiver for the intent and do what you must do.
Note that broadcast receivers timeout after aprox. 10 sec, so if you got a long task, use a service

Categories

Resources