I'm using
myLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
to retrieve the current location at the start-up of my application.
As the Android documentation states, this location can be "out-of-date", since the method returns the location when the GPS was used the last time.
How can I actively request the current location from the GPS? I thought about using LocationListener, however that might be a bit of an overkill, since I only need the location once (at the start of my app).
Any ideas?
Your initial intuition is correct - you need to use a LocationListener to request updates. Given that you require only a single position, you can unregister the LocationListener after the first value returns.
In practice though, it's probably wise to listen for a little bit longer. Location Based Services (particularly GPS) have a tendency to 'jump around' a bit when they first get their fix. Your best bet is to listen for a set amount of time, or a set number of updates, or until a certain level of accuracy has been achieved (the Location Listener will return the accuracy of the position returned).
Related
I'm building an app that should be able to report the users exact location. There is only a need for a single location, i.e. I don't need to track the device continuously.
I want the location to be as accurate as possible, and it's okay to wait a short while for the location to be determined (max 1-2 minutes).
I've been looking at FusedLocationProviderClient.getLastLocation(), but since I want the location to be as accurate and updated as possible it doesn't fit my needs.
So I started looking at using FusedLocationProviderClient.requestLocationUpdates() instead, and it seems like a better choice.
But I'm not sure how to best configure my LocationRequest to get as good accuracy as possible. For instance, would it be better to use setNumUpdates() so that I only receive a single update and use that as my location, or should I receive multiple updates in hopes of getting better accuracy (GPS locking to more satellites for example)? I'm thinking that if I use the second approach, I could look at the value of getAccuracy() from each location update and only keep the one with the highest accuracy. The downside is that if the device is moving and I keep receiving updates for a minute or so, the first location could have the highest accuracy, but since it's a minute old it's not accurate any more.
As stated above, I need just a single highly accurate location and it's okay for the app to wait 1-2 minutes for it if needed. What would be the best approach in this kind of scenario?
First, make sure the accurate location is turned on. look at Settings.Secure.LOCATION_MODE_HIGH_ACCURACY It has a noticeable advantage over only using GPS. Then listen for the location for a while and calculate the result you get to find out the best location. You can also detect if the user is moving if the number differs a lot or by using Activity Recognition API. It shouldn't be very hard to write this calculate function to get the best result.
I'm not sure about this but I really don't think waiting more than a few seconds gives you an advantage. to be sure you can simply alter this time and watch the result.
You might want to use LocationManager. In my experience FusedLocation will indeed appear to lock faster but may not be as accurate overall, or at least for a while. I have an app that also requires pretty accurate coordinates. My default is to use a LocationManager based approach but users can switch to a FusedLocation provider if they want faster locking (like when indoors).
This is a good overview https://developer.android.com/guide/topics/location/strategies
For the provider when requesting updates I'd use LocationManager.GPS_PROVIDER. It will take longer to lock since it will wait for satellites and not use Wifi or other towers. But you said that's OK. Something along these lines
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, YourLocationListener);
Once you start getting location updates via your listener's onLocationChanged() you can start to inspect the location for accuracy, movement from last location change, etc. to try and evaluate if the GPS receiver is still settling in on a location. Once you are satisfied with the quality of the fix you can stop receiving location updates (locationManager.removeUpdates(YourLocationListener)) and then run your logic that needs the location. The link I provided has good info about this 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.)
I just need to understand this clearly, getLastLocation() method will give me the last known location and requestLocationUpdates will give me the current location every period of time.
now, i am developing a simple app to track mobile phones, which will be in cars.
my Question are :
1- how exactly getLastLocation() works, will this last known location be updated when the location change
2- which is better, using getLastLocation() to have the initial location then update the current location by using the method onLocationChanged or using requestLocationUpdates to have an up to date location every n sec ?
getLastLocation gives you the last location which was there in LocationClient, it can be null sometimes, say if you don't have any other application installed which uses location services, that's a rare case as most phones have Google maps or some other location dependent apps installed.
getLastLocation is only helpful, when you want location for once and your done with it, but for location updates you should use requestLocationUpdates, and using a service, your application will always get notified, when the location changes.
I hope you are using the FusedLocation Provider from play services, so you can specify how fast location updates you need, to check cases of battery drain and performance.
Also to note here when you use requestLocationUpdates then only you will get any location change updates.
so according to android docs getLastLocation() :-
Returns the best most recent location currently available. If a
location is not available, which should happen very rarely, null will
be returned. The best accuracy available while respecting the location
permissions will be returned. This method provides a simplified way to
get location. It is particularly well suited for applications that do
not require an accurate location and that do not want to maintain
extra logic for location updates.
This is the problem with getLastLocation(),that it is not accurate and it may return null if it does not have any last known location in cache.I have faced this issue many times in my application.So for getting the accurate location you should use requestLocationUpdates() but define the interval according to your need at which time interval you want the updates as a very short time span may cause more power usage.
How can I get a single GPS fix of my location just by calling one function? Just for this example how can I get the Lat and Lon into a toast.
What have you tried?
Here are two of the official pages for location: http://developer.android.com/reference/android/location/Location.html
http://developer.android.com/reference/android/location/LocationManager.html
But to get the most recent location and show it in a Toast:
LocationManager locMan = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
Location loc = locMan.getLastKnownLocation(LocationManager.GPS_PROVIDER);
String lat = String.valueOf(loc.getLatitude());
String longitude = String.valueOf(loc.getLongitude());
Toast.makeText(context, lat+","+longitude, Toast.LENGTH_LONG).show();
If you want to request a new location, it is more code, and I will not cover that here. You can do some google searching or searching on here to find how to use it. The method you need is requestLocationUpdates or requestSingleUpdate. I'm guessing you would prefer requestSingleUpdate
I do not think that you can just make one call and get a location fix. GPS / Android just doesn't work that way. The phone may have a last known location, but that last known location may have been taken/recorded hours ago and miles away. The location returned by the getLastKnownLocation() method has a time stamp and an accuracy that can be used to see if the location is "good enough".
Locations are typically determined by setting up a listener, listening for updates and stopping the listener when you have a good enough fix. See Obtaining User Location for a good worked example, especially the details in the example isBetterLocation() method.
I find it best to create an Asynchronous task that actively registers and deregisters GPS/network/passive listeners depending on whether the application has a good enough location, or not, and have that class export a getMyPosition() method that returns a Location object if a good enough position has been established, or null if not. Then the main code can make a simple one line function call to get the current position. But only because there is an asynch task behind the scenes doing the hard work.
I try to make my asynch task actively deregister the GPS listener and turn off the GPS circuits to save battery live when I have a good enough fix. How long I turn off the listeners depends on the needs of the application. Leaving the passive listener left on (registered) allows my task/application to listen into the GPS position reports caused by any other application on the device "for free".
Getting a good enough position is not a one function call deal, unless you make it so with lots of behind the scenes work.
i'm working on app, which must get latitude and longitude. in my case requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener) is not in option. why? because i must get location just when user do something that location is needed (let's say he hits button). and i need location exactly on the time, when button is hit. in requestLocationUpdates, we can set minTime-if i set this let's say on 30000 the location at the "button hit time" won't be as good as i want. of the same reason minDistance is also not as good as i want. if i understant function requestLocationUpdates correct-when minTime and minDistance are set to 0, location is updating all the time. please correct me if i'm wrong. app is for company that i'm working at and that app will be used through the day and night. so if app will check for location updates all the time, battery would be often empty. thst's why i need location just at the time, that button is hit. i found requestSingleUpdate function. but i can't use it in eclipse =( like it doesn't exists.
is there some other way to do this or am i missing something?
The requestSingleLocation method new for API level 9. If you are targeting an earlier API level, this method will not be available to you.
One of the problems with obtaining location information is that it can take time to get a fix. This is more of a problem with the GPS location provider than the network provider. If you are only using the network provider, then there may not much of a delay with getting the location information when the user clicks the button (I say this knowing nothing about what your app does with the data, or what type of user experience you are trying to provide).
Something else you can try is the PASSIVE_PROVIDER. It allows you to get location updates that were requested from other apps. This will mean that you have to request the ACCESS_FINE_LOCATION permission however. You may also need to leave something running to receive the location updates (likely a service or a BroadCastReceiver). The BroadcastReceiver approach should not use that much additional battery life since it only runs when the Intent is received along with the PASSIVE_PROVIDER only getting locations when some other app requested them anyways.
The other sticky point with the PASSIVE_PROVIDER is that you should eventually call removeUpdates. Where and when to call this really depends on how your app is structured and how you handle the user exiting the app.
You can use getLastKnownLocation method, but it can be out-of-date. requestLocationUpdates is asynchronous because gps needs to "warm-up" to find new location.
requestSingleUpdate method is available since api level 9, but you can implements it's using requestLocationUpdates and disabling updates after first callback to LocationListener.