I have some code that runs multiple times per second in my app. I'm trying to get my location in every cycle. I am using the following:
Location myLastPos = LocationServices.FusedLocationApi.getLastLocation(googleApiClient)
My app also runs in the background using a PARTIAL_WAKE_LOCK. With the screen on everything seems OK. When I turn the screen off my app still runs normally but I no longer get location updates consistently.
It appears that I get updates much less frequently (often minutes in between updates). I'm checking the timestamp of the location using:
myLastPos.getElapsedRealtimeNanos()
I also found that even when the screen is on I get some strange results. Sometimes I get a few milliseconds between updates, other times I get a few seconds. This is all very concerning. Can someone either help me use FusedLocationApi properly or suggest an alternative. All I really want is to poll the gps directly for lat/long a few times a second without google libraries getting in the way.
The getLastLocation() method just gets the last known location that the device happens to know. The "last known location" here means exactly that: It may not be up-to-date. Locations do come with a time stamp which could be used to asses if the location might still be relevant.
The device doesn't determine its location on its own, but only when some application request the location. So your app is now dependent on other applications requesting location updates.
If you need updates every few seconds, then request regular location updates yourself.
Android documentation recommends the FusedLocationProvider, but the LocationManager is also a perfectly valid option, if there's any reason to avoid the Google Play services.
The basic idea is to first request location updates:
// Using LocationManager as an example.
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Using GPS, requesting location updates as soon as available and even for
// the smallest changes. Here 'this' refers to our LocationListener
// implementation.
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
The updates are then received by a listener:
#Override
public void onLocationChanged(Location location) {
// We received a location update.
// Copy the value from the method parameter to our
// class member variable.
mLocation = location;
}
And when you no longer need the updates you should cancel the request:
mLocationManager.removeUpdates(this);
The approach is very similar for the FusedLocationProvider.
Related
I'm starting to develop an app that will stay in background forever and detect when a user is staying in a certain location for a while (and then display a notification to invite the user to open the app to obtain informations about that place).
It's something very similar to what Google Maps does when you're in a restaurant and it shows you a notification to check ratings about it.
What I want is to have a minimal impact on device, so location updates should be very "passive", getting the location only when user is not moving and, if possible, recycling location data that is already got by other activities - maybe by Google Maps itself or other location apps that are running on the devices.
This is not a navigation app, so I don't need to have the live fine location but simply the approximate place with the best accuracy and minimal effort, and only if user is not moving.
LocationListener and onLocationChanged seems to be my men, but can I specify that I don't want to trigger device's sensors and only re-use location data when it's available for other scopes? My app should check these informations and then decide to do a reverse geocode if and when they are accurate enough.
Yes, LocationListener and onLocationChanged are your men, though for a passive implementation, there are a few options you can go through.
First you can check for the last known location, maybe compare it in terms of its time; i.e. getTime() and verify whether it is of use to you.
In terms of code, literally...
Google samples, android location has what is relevant for the last location part:
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Provides a simple way of getting a device's location and is well suited for
// applications that do not require a fine-grained location and that do not need location
// updates. Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Further, you can combine it with LocationRequest object, this helps your implementation as you can call it right after trying getLastLocation() and basically have a more reliable arrangement for obtaining location.
// Create the location request
mLocationRequest = LocationRequest.create()
//priority object needs to be set, the following will definitely get results for you
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
//interval updates can be on the lines of 15mins or 30... acc to your requirement
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
i suggest give PRIORITY_NO_POWER a try, could work well in combination with getLastLocation(). These power modes have been added specifically for optimising battery/power consumption and efficiency for retrieving location.
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.
I want to get 5 consecutive update locations in order to check if the user is moving and to make sure the GPS is calibrated. I did the following:
I added android.permission.ACCESS_FINE_LOCATION" to the manifest and in onConnected:
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000); // Update location every second
mLocationRequest.setFastestInterval(1000);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
and in onLocationChanged I did the following:
locationRetries++;
switch (locationRetries) {
case 1: {
firstLatitude = location.getLatitude();
firstLongitude = location.getLongitude();
}
case 5: {
locationRetries = 0;
lastLatitude = location.getLatitude();
lastLongitude = location.getLongitude();
accuracy = Math.round(location.getAccuracy());
stopLocationUpdates();//will remove from location updates and disconnects
float[] results = new float[1];
Location.distanceBetween(firstLatitude, firstLongitude, lastLatitude, lastLongitude, results);
if (results[0] > 5)... //if moved at least 5meters, show popup that the user is moving else do your thing
}
Now I have 3 issues:
1) It seems to take much less than 5 seconds to retrieve the 5 updates even though I set both parameters to be 1000 milliseconds.
2) All the 5 locations (at least the first and last ones) are the same exact location even though I was walking fast. I thought I maybe moving too slow so
3) I closed my app, reopened it on a far location and pressed the button. Almost instantly I got the previous location. I pressed the button again and then I got the real location I was on. It's as if it didn't really asked/waited for a location from the GPS but instead took the last one which was remotely inaccurate at the time. I don't have any "get last known location" code.
I guess the bottom line would be: how can I make sure that it really asks the GPS where am I when I asked for the location and also when asking it for 5 consecutive times, to give me the real locations and not from the cache(?).
The Fused Location Provider
intelligently manages the underlying location technology and gives you the best location according to your needs.
Simple APIs: Lets you specify high-level needs like "high accuracy" or "low power", instead of having to worry about location providers.
Immediately available: Gives your apps immediate access to the best, most recent location.
Power-efficiency: Minimizes your app's use of power. Based on all incoming location requests and available sensors, fused location provider chooses the most efficient way to meet those needs.
Versatility: Meets a wide range of needs, from foreground uses that need highly accurate location to background uses that need periodic location updates with negligible power impact.
There is no guarantee that the fused location provider will ever use GPS - if it has a recent location of the accuracy you request it will return until a better location is returned (i.e., live GPS is returning accurate locations). This ensures that you'll get a better location sooner without waiting for GPS to be primed.
If you specifically need data from GPS, you need to use the LocationManager using the GPS_PROVIDER.
If you are trying to determine what the user is currently doing, you can instead use the ActivityRecognitionApi, which returns DetectedActivity such as WALKING or STILL: using that would give a faster method to understand what the user is currently doing.
I am developing an android application wherein I need the user location updates pretty frequently. Say 2 times a minute.
Earlier I had been using Google Play Service's "Fused location service" but the location updates were not received as requested.
The location updates got stuck for sometime, the interval between updates jumped to 10min or so.Sometimes even if I put my priority to "PRIORITY_HIGH_ACCURACY" the same happened.
I then went back to the old "Location Manager" and when I used the "NETWORK_PROVIDER", I noticed that the location updates got stuck due to this provider. Also the GPS does not get activated immediately, it takes some time. I am trying to build my custom fused location provider. How can I efficiently switch between providers, without getting lags on location updates.
I want to know what are the best practices for getting location updates regularly, all the time, be it either NW, GPS or both. Like it should work for an application where location updates getting stuck cannot be afforded.
Battery drain is not an issue for me right now.I am aware of all the supporting docs that Google provides regarding location access.
Any help would be much appreciated.
Thankyou !
FusedLocationProvider really is the best option for obtaining locations at the moment, because it uses a lot more than just GPS or Network data to obtain location fixes. I have experienced issues regarding intervals being missed as well, but ultimately this is something down to luck depending on availability of GPS, Network, etc. etc.
My favourite usage of FusedLocationProvider so far is in conjunction with the AlarmManager class: Basically, the idea is to start location tracking at intervals specified by the Alarm Manager (this can be set to every 30 seconds such as in your case). Once the interval is hit, the location provider is to obtain a location fix as soon as possible (so in the setInterval method or whatever it's called, the parameter is a 0). This way, you can avoid having to wait another 30 seconds for a new location, instead having the location tracker attempt to provide a location as soon as possible after the interval specified by the Alarm Manager is hit.
By the way, when making custom location tracking wrappers, be careful of using the .getLastKnownLocation() method as it only uses cached locations - you could end up sending the same location to the user every 30 seconds.
Good luck!
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.