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
Related
My goal
Get user location updates for quite long time (e.g. 8 hours) with quite high frequency (e.g. every 30 seconds) even when the application is not running in foreground (meaning the activity where the location tracking was started might be destroyed).
Issue
I've found many articles regarding location tracking in Android apps.
The newer ones usually explain how to use Google Play Services' location APIs.
The problem is that in most cases, they demonstrate getting location updates in co-operation with Activity and LocationListener. For example in Google's tutorial. It's obvious this is not what I need. The only approach for long-running background location updates was based on periodical starting (via AlarmManager) of a service that run until it got accurate enough location update. However, this approach doesn't seem right for the frequency I need.
So, I ended up with custom idea how to solve the topic, but your critique would be welcomed. Here it is:
Idea of a possible solution
MainActivity - used just for starting/stopping the tracking by starting/stopping the MonitoringService
MonitoringService - a foreground service, where the whole connecting to LocationServices from Google Play services happens. Also, once connected a requestLocationUpdates method is called, but its variant with PendingIntent object. The pending intent contains intent invoking MyWakefulBroadcastReceiver class. Also, the service holds a partial wake_lock to prevent the device going to sleep and interrupting receiving of the location updates. Here, I'm not sure if holding the wake lock really helps.
MyWakefulBroadcastReceiver - extends WakefulBroadcastReceiver, just starts LocationProcessingIntentService via the startWakefulService
LocationProcessingIntentService - processes the location update passed via intent to it. Network communication performed here. Therefore, it is done in separate service and not directly in the MonitoringService
Currently, I have the solution described above implemented without acquiring the partial wake lock in the MonitoringService. When connected to debugger in Android Studio, I see the processing of the location updates work. However, I'm not sure what it will do after e.g. 4 hours of running without being connected to laptop (like it is for the debugging purposes)
Questions
Is this approach OK from architecture/performance/battery life point of view?
Should I use the wake lock for being sure the device won't go to sleep?
If answer to 2. is yes, do I still need to use WakefulBroadcastReceiver for starting the IntentService processing the location updates?
Any other recommendations?
What you have is mostly fine. You don't need the MonitoringService. The PendingIntent will wake your BroadcastReceiver, regardless of the state of your app. You don't need a permanent wake-lock. Just use the PendingIntent in your setup Activity to requestLocationUpdates.
Remember that the location services are already running in the background (as long as the user has enabled location services), so you don't need to run your permanent wake-lock service also (you can wake-lock after BroadcastReceiver#onReceive(), but don't forget to release the wake-lock after processing).
The only time you might have to worry about the PendingIntent not waking your BroadcastReceiver is if the user force-stops your app. In that case, you could choose to respect the user's decision. You can also explore using intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); which should wake your BroadcastReceiver from the stopped state, but I haven't tested this flag in this scenario.
Problem:
The user can choose how long and when start to track your locaton (Like today from 08:00 to 16:00). So during this interval my application will listen for the location every 5 minutes (this time can be changed, it's a user's preference).
What I'm thinking:
Making a service to be running and listenning for coming of the GPS or network locations during the time interval definned by the user.
Problem:
The service can be removed for running a long time?
I need to registers listeners to GPS and Network (even if they have not enabled) when starting the service or I need to register and remove Listener depending status of GPS and Network?
My service will continue running even if the user is not using the phone for a long time (like an hour) right?
You don't need to register a Service for this. You can use Mak Murphy's cwac-locpoll library.
This is a short description of the library taken from the page linked above. You'll also find code examples there.
You simply set up an AlarmManager alarm to contact LocationPoller on whatever frequency you wish, and it will handle all of the location work from there, sending you the results via a broadcast Intent. Your BroadcastReceiver can then use the location data as needed.
I developing an app which tracks a user via GPS and reminds them if they cross a toll bridge.
I obviously need the GPS location listener to run in a service and I'll also need a partial-wakelock so it can run occasionaly when the phone is asleep.
I also want the GPS updates to vary in frequency depending on the distance from the toll bridge to save battery.
The cwac- WakefulIntent service seems ideal for what I'm trying to achieve.
However, there are a couple of problems I can see me having before I head down this route (if you pardon the pun ;-).
Does the WakefulIntent service exit and release the wakelock once doWakefulWork() completes even if I'm waiting for my locationlistener to return some GPS updates.
How can I prevent doWakefulWork for returning until I get a location update and cleanup my listener.
What happens if I'm still waiting for a GPS update when alarm manager starts the service again, i.e. before doWakefulWork() has completed?
How can I persist data between instanciations of the service. Can I stuff an array of GPS co-ords into SharedPrefs?
Finally, as I get closer to a toll bridge I need more GPS frequent updates. Do I manage that within doWakefulWork() or by altering scheduleAlarms() so that it uses setRepeating() with a number of minutes stored in SharedPrefs by the service. The idea here is to throttle GPS usage based on proximity to an area of interest.
While the demo app provides a template to work from, I haven't been able to find any solid examples of WakefulIntentService doing any asynchronous jobs.
The cwac- WakefulIntent service seems ideal for what I'm trying to achieve.
Not really. IntentService is not good for location tracking, because you cannot register a listener. The service will shut down once onHandleIntent() ends.
Personally, I would use addProxmityAlert() on LocationManager, rather than mess with any of this yourself.
Does the WakefulIntent service exit and release the wakelock once doWakefulWork() completes even if I'm waiting for my locationlistener to return some GPS updates.
Yes.
How can I prevent doWakefulWork for returning until I get a location update and cleanup my listener.
You don't. You use something else, such as LocationPoller, or, better yet, addProximityAlert().
What happens if I'm still waiting for a GPS update when alarm manager starts the service again, i.e. before doWakefulWork() has completed?
You ensure that you have appropriate timeout logic in place to prevent this, such as can be found in LocationPoller.
How can I persist data between instanciations of the service. Can I stuff an array of GPS co-ords into SharedPrefs?
Yes, or a database, or a file in a format of your choosing.
Finally, as I get closer to a toll bridge I need more GPS frequent updates. Do I manage that within doWakefulWork() or by altering scheduleAlarms() so that it uses setRepeating() with a number of minutes stored in SharedPrefs by the service.
You would change your alarm schedule.
I haven't been able to find any solid examples of WakefulIntentService doing any asynchronous jobs.
WakefulIntentService is the "asynchronous job". It does not execute other asynchronous jobs.
I set an alarm with the flag RTC_WAKEUP to run a IntentService every 30 seconds to transmit location updates to a server. I'm planning to change the flag to RTC so it won't wake up the phone and just run when another process wake ups the phone. If I leave a LocationListener registered, will it still listen for location updates while the phone is asleep?
Yes - working location service has it's own wake lock. However better approach is manually set proper wake lock in your broadcast receiver. Please consider some optimization - sending data over network every 30s will drain battery.
You have multiple problems here.
I set an alarm with the flag RTC_WAKEUP to run a IntentService every 30 seconds to transmit location updates to a server.
First, you may not even get your first fix within 30 seconds, particularly if you are using GPS. You need to take into account that you may never get a fix (e.g., the user is in an underground location).
Second, please allow this figure to be user-configurable, including an option for "I'll upload the data manually please". As #piotrpo indicates, this is a significant drain on the battery. In fact, if you're using GPS, I doubt the battery will last more than a couple of hours.
Third, an IntentService will not work well in this case, because the IntentService will shut down before your fix arrives. At best, you'll leak memory. At worst, you won't get your fix, because Android terminates your process.
A better solution for doing background location checks is to use a regular Service, not an IntentService. The regular Service would register the LocationListener in onStartCommand(), plus arrange for a timeout notification (e.g., AlarmManager and set()) in case a fix is not available. When the fix arrives, run an AsyncTask to do your upload. When the AsyncTask completes, or if the timeout arrives and you did not get a fix, unregister the listener and call stopSelf() to shut down the service. Along the way, you will need to maintain your own WakeLock, to keep the device awake while all of this is going on.
For an example of most of this (minus the server upload part), see my LocationPoller.
If you are dead-set on this occurring every 30 seconds or so, you may as well not bother with AlarmManager at all. You would have to have an everlasting service, running all the time, with a permanent WakeLock and a permanent LocationListener. When fixes arrive in onLocationChanged(), upload them if they are more than 30 seconds from the previous one. And, be sure to wear a flame-retardant suit when you release the app, as those who run it may not like the results much.
I would like to write an app on Android to upload my GPS location to an external website once every ~5 minutes. This needs to have as minimal an impact on battery life as possible, but it also needs to work without any user interaction. (Background: I'm competing in an Ironman triathlon which will take me about 14 hours to complete, and want to broadcast my location in near-real-time but without having to worry about fiddling with my phone.)
So my initial thought is to write a Service which uses LocationManager.requestLocationUpdates() with a minTime of 5 minutes, but will this actually wake the device up every 5 minutes for my service to do its job?
It sounds like I would also need to use AlarmManager.setInexactRepeating() to make sure my service is awake while it completes its task but how does that play with requestLocationUpdates()? Should I instead set minTime=0 on requestLocationUpdates() but then go back to sleep as soon as the next update is obtained?
Any general guidance on how to design this is greatly appreciated. I'm a competent Java programmer & will be using Google Maps on the server to plot my location, but am pretty new to Android development so I'm basically looking for a high-level plan on how to architect the client app.
Your service must be alive all the time you want to receive updates.
http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates%28java.lang.String,%20long,%20float,%20android.location.LocationListener%29
You can tell how often you want to be informed of location change with minTime parameter. It does not however decrease battery consumption. GPS is enabled unless you use removeUpdates method no matter how often you want to receive updates.
You can use another approache:enable GPS using method above, read one value, use removeUpdates method, wait 5 minutes and all over again. Delay between enabling and retreiving a location can be between few seconds to few minutes.