Porting our location based game to Android.
We rely on updating user location when the app is in the background. What's the best way to accomplish this on the Android side while mitigating battery impact?
We don't need high-frequency updates, even 20 minute cadence is acceptable.
Thanks for any help
You will need to create a Background Service in order to accomplish what you want.
Inside that Background Service you will need to use LocationManager and request for Location Updates.
The function that request for Location Updates takes parameters for the fixes intervals as shown below:
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)
you will use the minTime parameter to choose the interval between the fixes:
minTime : the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
Related
I need a background service which runs continuously for my app. I looked online for different ways like foreground service which continuously shows notification for versions above android 8, Work Manager and Job Scheduler. I think Work Manager suits my requirements in terms of background running but not sure whether it can be triggered based on the location distance change.
https://developer.android.com/topic/libraries/architecture/workmanager
I see that we can have periodic updates like every 15 min but wanted to know if we can configure based on location distance change itself.
https://medium.com/#prithvibhola08/location-all-the-time-with-workmanager-8f8b58ae4bbc
Example if I set setSmallestDisplacement(10m) for location request, the worker manager should be triggered every 10m distance change and send location to server.
https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest
For my app, I'll let the location services run with no schedule. But I'll specify the minimum distance changed in my location manager to call an update like this.
private void onStartListening() {
//init location manager.
LocationManager mLm = (LocationManager) getSystemService(LOCATION_SERVICE);
//binding listener to manager with network provider.
mLm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 10, mNetworkListener);
}
The third argument for my requestLocationUpdates() is the minimum distance between location updates in meters.
Also, the second one is the minimum time interval between location updates in milliseconds. If you want to specify time criteria for your location updates too.
I have used onLocationChanged method of LocationListener for detecting change in location of my device. In requestLocationUpdates method I have set minimum Time = 5 seconds and minimum Distance = 2 meters, but requestLocationUpdates method is giving me updates even when my device is not moved at all (placed stationary). So please tell what is the issue with my code?
This my code:
public class LocationDetector implements LocationListener {
#Override
public void onLocationChanged(Location location) {
Log.d("GPS: ",location.getLatitude()+", "+location.getLongitude());
}
.
LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
.
manager.requestLocationUpdates("gps", 5000, 2, new LocationDetector());
The GPS location can fluctuate. If you actually log the locations that you receive, you'll probably see that the location actually changes by 2 meters or more whenever a location update comes.
Edit: Ideas for dealing with the fluctuation added:
How to deal with GPS fluctuation depends on your application's needs. Some possible ideas include:
If you don't need a really accurate location, then use a higher distance limit in the requestLocationUpdates() call to not receive updates for very small location changes. You can think what's the absolutely necessary accuracy required by your use case and then use the highest possible distance limit.
If you don't expect the location to change very quickly or you don't need to react to location changes very quickly, then use a higher time limit in the requestLocationUpdates() call. This also makes sense if you have some very heavy code triggered by onLocationChanged() like if you always fetch some data over the network (reverse geocoding etc.).
The time limit also has more impact on the battery usage. Android documentation says:
...it is more difficult for location providers to save power using the
minDistance parameter, so minTime should be the primary tool to
conserving battery life.
If you really need an accurate location then there are some ways to decrease the fluctuation.
First of all the Location object received in onLocationChanged() usually has an estimated accuracy available by calling the Location.getAccuracy() method. You can simply ignore any location updates that have very poor accuracy (compared to the accuracies of previous location updates).
You can also do some filtering if you have a short buffer of the most recent locations. Calculating an average will reduce the amount of sudden changes but it also increases the response time. That is: a rapid change in the location will completely show up in the averaged location data only after some time. (Of course the averaged data starts to move towards the location right away, but it takes a while.) Also it will "let the spikes trough" to some amount.
If a fast response time is important and any major "spikes" in the data should be eliminated, then calculating the median is a better option. It will not smooth out the small changes in the data that much, but random spikes can be filtered out. If there's a real (permanent) sudden change in location, then the median filtering reacts to that with only a very small delay.
(These things are easy to try out in your favourite spreadsheet application.)
Android programming is a brand new thing to me, i've been playing with android's location and i have a same issue, im going to send a periodic location updates to a server in background and i'm using the AlarmManager/LocationManager approach, set an alarmManager with a defined Interval then when the alarmReceiver is triggered it will get device's current location (using locationManager) and send it to the server on its onReceive method. i found out this FusedLocation as a great replacement as LocationManager give me an additional job to get the best location provider. is it possible to perform sending location updates in background periodically using fusedLocation api without an alarmManager? if so, how can i do that? thanks in advance!
Per the LocationRequest documentation:
In between these two extremes is a very common use-case, where applications definitely want to receive updates at a specified interval, and can receive them faster when available, but still want a low power impact. These applications should consider PRIORITY_BALANCED_POWER_ACCURACY combined with a faster setFastestInterval(long) (such as 1 minute) and a slower setInterval(long) (such as 60 minutes). They will only be assigned power blame for the interval set by setInterval(long), but can still receive locations triggered by other applications at a rate up to setFastestInterval(long). This style of request is appropriate for many location aware applications, including background usage. Do be careful to also throttle setFastestInterval(long) if you perform heavy-weight work after receiving an update - such as using the network.
This allows you to guarantee you'll get location updates based on the interval you set with setInterval(long), giving you the equivalent behavior to a periodic alarm, but if other apps request location information, you may get location information as often as your setFastestInterval(long) - you can set your fastest interval to your interval if you just want location updates at a set interval.
I need to get GPS location updates every minute (battery life isn't a problem as the device(s) will be charged within the vehicles). It's a company delivery app, with vehicle tracking, used in conjunction with Google maps, to track journeys for delivery planners etc.
I've used both AlarmManager and LocationManager.requestLocationUpdates() with a listener. The later seems a bit ropey and going by the documentation, it may or may not give a location. But I've seen that even though the minTime is set to 1 minute and distance is 0/1, I'm still only seeing updates once or twice per 5 min period.
private void startGeoLocationSender()
{
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new GeoLocationListener(this);
// MINIMUM TIME TO REQUEST , MIN DISTANCE TO REQUEST, LISTENER
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
AppSettings.COLLECTOR_PROC_1_MINS,
AppSettings.COLLECTOR_DISTANCE_1_M, locationListener);
}
So, is it worth me just going back to an AlarmManager and forcing an update manually for it to be reliable? Or is there another method, which is 100% reliable given a specific update time? What is better suited to my requirement?
PS. I'm very aware of the other '000s of topics on the subject, but I've never seen such a Good Vs Evil trend. Some folk swear by location listeners, and others only AlarmManagers.
I am not sure of a better way, so I would recommend AlarmManager.
If you use only LocationListener you can't ensure that will receive update in interval time needed.
I really think that the best option is the AlarmManager or a Scheluder Service with a trigger to your LocationListener.
In my application, I have calculated speed based on GPS locations.
As GPS receiver can have different coordinates even being on the same location, my app is recording speed even when phone is on my desk.
I need to avoid GPS data if I am receiving it being on same location.
I am thinking of adding some logic based on “bearing”, so that I can decide if the phone is actually moving or it’s receiving jumpy location data from any direction.
Before that I would like to know is there any other way to avoid this kind of data?
AS per the Javadoc for the method request public void requestLocationUpdates (long minTime, float minDistance, Criteria criteria, PendingIntent intent) found here
minTime minimum time interval between location updates, in
milliseconds minDistance
minimum distance between location updates, in
meters
so you can use minDistance parameter to avoid getting update for very short distances...
After working on many methods I programmed it with bearing.
I am getting speed based on last 5 locations. I added Logic to check bearing for each location with next location and if all bearing have larger difference, I assumed locations are being received from random directions and so the device is not actually moving.
And it worked great for me :)