I wanted to know what is the most battery efficient way to send accurate location updates to server/firebase every 5 seconds, even if app is closed or phone is rebooted. I tried using AlarmManager.setRepeating along with android.intent.action.BOOT_COMPLETED receiver-
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
5*1000, // 60000 = 1 minute,
pendingIntent);
But this doesn't work on Android 5.1+ due to -
Frequent alarms are bad for battery life. As of API 22, the
AlarmManager will override near-future and high-frequency alarm
requests, delaying the alarm at least 5 seconds into the future and
ensuring that the repeat interval is at least 60 seconds.
Using post a delayed message or runnable to a Handler is not a reliable solution because as soon as application is swiped off location updates are stopped.
Is there any reliable way to send accurate location updates to server every 5 seconds?
Firstly (if you haven't already) - check out Google's FusedLocationProviderApi which is designed to be network/battery efficient when it comes to location updates.
Also, have you looked in to GCM Network manager? This was designed to allow for battery efficient tasks (either one-off or recurring). It tries to batch those tasks them with other network requests to save multiple activiations of the device's radio. (Here's a short explanation)
Related
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
I'm developing an app that checks the weather based on the current location every 3 hours. I'm getting the location using the FusedLocationProviderApi and using a pendingIntent to a BroadCastReceiver that start up an IntentService.
In the FusedLocationProviderApi you can specify an interval period when you are creating the LocationRequest. So if I specify the interval to be 3 hours and the fastest interval as well to be 3 hours (I don't want to get updates before that), what happens if location is not available when it's time to do a location update?
Will I still get the location update intent at the scheduled time? I would like to use the last known location if the location is not available, but I need to be certain that I am still getting the PendingIntent at the scheduled time.
Or is it better to use an alarm manager to handle the periodic work and request the location update from within the IntentService instead?
Thanks
In the FusedLocationProviderApi you can specify an interval period when you are creating the LocationRequest. So if I specify the interval to be 3 hours and the fastest interval as well to be 3 hours (I don't want to get updates before that), what happens if location is not available when it's time to do a location update?
In this scnerio device must be awake to keep alive your location request. So it means you must have a non-stop(theoretically) background service, and partial wake lock as well. They sound not good.
Instead, you could refer AlarmManager approach which is set to wake up at each 3 hours. Then idea works like below
Device wakes up
Makes location request asap (set interval values to zero)
Continues to sleep after receiving location (and also doing your actual work)
I'm trying to make an optimized application that runs background 100% of the time.
It receives location updates and post them to a server.
I'd like to know if im doing things the way i should.
At this moment my app has a service that requestLocationUpdates using LocationServices API.
It accumulate locations and try to send them to the server.
This services is self terminated if no more locations are pending left.
Also i have an alarm to wake up this service every while.
So next time the service wake up, start a new session of GooglePlayServices and receive locations again.
I understand that using pendingIntents is better for unmanaged location tracking, but i still think that need the background service to upload locations in a timely manner.
- Should i stop using alarm raised services?
- Is there any way to start requesting location updates without user intervention / activity?
- Is a broadcastReceiver capable of managing heavy work like network posting?
Got this from google locationServices doc:
public abstract PendingResult<Status> requestLocationUpdates
(GoogleApiClient client, LocationRequest request, PendingIntent
callbackIntent)
Requests location updates with a callback on the specified
PendingIntent.
This method is suited for the background use cases, more specifically
for receiving location updates, even when the app has been killed by
the system. In order to do so, use a PendingIntent for a started
service. For foreground use cases, the LocationListener version of the
method is recommended, see requestLocationUpdates(GoogleApiClient,
LocationRequest, LocationListener).
Thanks in advance
Is there any way to start requesting location updates without user intervention / activity?
Yes, you can create nice scenarios setting up alarm with specified frequency. Even the app is not working, your alarm wakes up device, receives location and then sends to server. After it's work done, device sleeps again. Please check this project, here super scenario from commonsguy.
Is a broadcastReceiver capable of managing heavy work like network posting?
Yes, it does, You'll probably send location to server.
Should i stop using alarm raised services?
Depends on your tracking style.. Consider examples
Receiving location and sending to server at every 10 minutes (or more)
Receiving location and sending to server at every 5 seconds (like realtime tracking)
Probably, for the first example, you will set repeating alarm and then wake up device, receive and send location, and finally allow device's sleep (10 minutes). In this case, you must stop everything about tracking (location services, network operations)
But in the second example, you cant set alarm with lower frequency like 5 seconds. You should have not-stop background service (theoretically) and make location request with 5 seconds interval. In this case, you shouldn't stop resources like (awake device, location requests, network operations). And finally user uninstalls the app :-)
Bottom line, follow commonsguy's project
Scenario:
Post to server to get any new data in background every 30 seconds for long period i.e. 12 hours. Location data needs to be sent along with this.
Current Implementation;
Service Class;
Location listener with interval of 30 seconds which sets the longitude & latitude values to two local variables
Alarm manager fires pending Intent every 30 seconds to a broadcast receiver.
Broadcast receiver starts an IntentService with location variables in the extras.
The IntentService http posts location and asks for any new data from server.
IntentService send server response back to main service class via broadcast receiver.
Service class starts_sticky to ensure restart by the OS.
I have tried a few different variations;
I've tried using a Handler and runnable to handle the timing mechanism for posting to the server however, the postDelay time went from 2 minutes to 7 minutes when device is asleep.
Also, tried firing IntentService directly from alarm manager but could not change PendingIntent extras with the most up-to-date location variables.
Questions;
Is the current implementation the way to go?
Would going down google's GCM route be much more beneficial?
How can you vigorously test the service class especially with respect to recovering from the OS killing it?
Thanks in advance.
To avoid the OS to kill your service, you must notify the user that your service is an ongoing service, like described in http://developer.android.com/guide/components/services.html#Foreground.
I managed to have my service running every 2 min at background using AlarmManager and WakeLock, like described in this answer. Even when the device is sleep, it runs every 2 minutes. Just set the Alarm to repeat like
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+5000, 60000 * ALARM_PERIOD_IN_MINUTES, alarmPendingIntent);
instead of setting it to a time.
I have an asynctask which retrieve data from webserviece. I want to run this task every 5 minutes to get the updated data from the server, but till now I don't know how can I do it.
I tried this code but my AsyncTask didn't stop
//...
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
new AddStringTask().execute();
}
}, 0, 5000);
As being suggested from others, you should use Push (GCM) instead of Poll. taken from this say:
Poll might easy to implement, but you will never be actually
real-time. If you polling interval is 30 min, you can get a message
that is 29 minutes and 59 seconds late. Moreover, polling more often
than every 15-30 min will kill your battery pretty quickly:
https://labs.ericsson.com/apis/mobile-java-push/blog/save-device-battery-mobile-java-push
As Michal K said, you can use AlarmManager with a Service and/or BroadcastReceiver to wake your app periodically.
However, in order to preserve the user's battery I highly recommend not polling the connection.
Instead, you can use Google Cloud Messaging for Android or GCM (formerly called C2DM)
Here's the site:
http://developer.android.com/guide/google/gcm/index.html
EDIT
The main benefit here is that Android phones that have Google accounts will already poll Google's servers periodically. They do this with cooperation from the carriers (like Verizon/AT&T). Because of this, the radio can go into low power mode and receive push notifications. By using Google's service, you enable a way for your app to receive data via push notifications without causing any extra battery drain.
====================
(Also, here is some of the info from my other post about this).
There was a very interesting Google IO talk this year about how the cell radio sits in an idle/low-power state most of the time, and takes a few seconds to "warm up". They also discuss the perils of how polling the internet periodically will really drain the battery.
http://www.youtube.com/watch?v=PwC1OlJo5VM
Battery talk starts about 17:12
http://www.youtube.com/watch?v=PwC1OlJo5VM&feature=player_detailpage#t=1032s
A slide from the presentation: