I'm writing an app that monitors the user's location. I have a CLLocationManager object that uses startMonitoringSignificantLocationChanges, so I can get locations updates from the background when the app is not running. I have setup my application didFinishLaunchingWithOptions so if I get a location key I fire up my manager to get the user's location. Everything works fine but the problem is that every time I get a location from the background, the Horizontal Accuracy of this location is very bad. In most of the cases it is 1414 m.
Does anybody know why the horizontal accuracy is so bad when the location comes from the background? Is there anything I can do to get locations with better accuracy in the background?
When the app is running all the locations I get are very accurate, this only happens when the location comes from the background. Does that have anything to do with the number of cell towers I have in my city? I was thinking maybe the device doesn't use gps of wifi nodes to get locations in the background.
Anyways, Any help here is appreciated. Please share your thoughts.
Thanks!
The accuracy of locations returned by CLLocationManager
is determined by the desiredAccuracy
, which is by default, kCLLocationAccuracyBest
, and by the available accuracy of the device. For instance, you may get less accurate locations if the device's battery is low, or you may get more accurate locations if they are still cached from another app.
However, getting you incredibly accurate coordinates drains a significant amount of power from the battery and will drain the device. Applications in the background are probably limited to a much lower resolution of accuracy to improve battery performance.
Accurate locations require a lot of power to use the GPS radio while less accurate locations can rely on nearby wifi hotspots and the cell towers within range of the phone.
As your application resumes from the background, the system will try to improve the accuracy of the results you get. It's a tricky concept, but take a look at the Maps application on your phone. At first, the circle representing your location is very large; as the system gets a more accurate sense of your location, the circle becomes smaller. This visualization represents the phone using more power to get a more precise location.
You'll see a similar phenomenon with CLLocationManager
as your app resumes from the background: you'll get an inaccurate location and receive subsequent, more accurate updates.
It's a compromise between convenience and battery life that Apple had to make when designing their APIs. The first update to a user's location probably won't be that accurate unless they were just using the Maps application and the location is cached.
The best advice I can give you is to listen for subsequent updates from the location manager and update your UI accordingly. Good luck!
As the name states: The startMonitoringSignificantLocationChanges notification is only there to let you know that a the the user's location significantly different from the last one checked. It's your job when you receive that Notification to update your location according to the desired accuracy you want.The notification won't do that for you. It is only going to let you know the location has change so you can deal with the situation accordingly. If you don't know how to get a better accuracy you may want to check out the Apple sample code for LocateMe.Here's a snippet that stores the accuracy(bestEffortAtLocation) then tests the accuracy each time the delegate is called until a better result comes in or a time-out occurs.:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// store all of the measurements, just so we can see what kind of data we might receive
[locationMeasurements addObject:newLocation];
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// test the measurement to see if it is more accurate than the previous measurement
if (bestEffortAtLocation == nil || bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy) {
// store the location as the "best effort"
self.bestEffortAtLocation = newLocation;
// test the measurement to see if it meets the desired accuracy
//
// IMPORTANT!!! kCLLocationAccuracyBest should not be used for comparison with location coordinate or altitidue
// accuracy because it is a negative value. Instead, compare against some predetermined "real" measure of
// acceptable accuracy, or depend on the timeout to stop updating. This sample depends on the timeout.
//
if (newLocation.horizontalAccuracy <= locationManager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
//
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
//
[self stopUpdatingLocation:NSLocalizedString(@"Acquired Location", @"Acquired Location")];
// we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stopUpdatingLocation:) object:nil];
}
}
// update the display with the new location data
}
The credit goes to Apple because this is a snippet straight from their sample code LocateMe:
http://developer.apple.com/library/ios/#samplecode/LocateMe/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007801-Intro-DontLinkElementID_2
So when you get the notification and need to get a better result you'll need to update the accuracy and see if that gives you a better result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With