In my app the GPS takes too much time to get the location.
How can I use GPS from GPS_SATELLITES and GPS _NETWORK_PROVIDERS simultaneously in the same context and get the value of the recent GPS?
Keep track of a Location object that is your current location. Request location updates from both
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
LOCATION_UPDATE_FREQUENCY, LOCATION_UPDATE_MIN_DISTANCE,
gpsListener);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_UPDATE_FREQUENCY,
LOCATION_UPDATE_MIN_DISTANCE, networkListener);
then when you get a response in onLocationChanged of either listener, either simply replace the Location variable you stored or replace it only if it is X seconds more recent, X% more accurate, X meters distant from your last reading, etc.
You can also use LocationManager.getAllProviders(), then call LocationManager.getLastKnownLocation(provider) to retrieve the last location each available provider found the last time it was called. This way, if another app used the GPS a minute ago, you can just go ahead and trust that they user hasn't made it that far away without hunting for satellites all over again.
Related
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.
I know with the Android and the Location API's it's possible to receive periodic updates of latitude and longitude through an interval of time using the "setInterval" method and other methods on the "LocationRequest" class, but what I'm wondering is, what would be a good way to get latitude and longitude updates via GPS based off of a change in distance compared to the previous location without having it on all the time and not wasting battery (preferably a solution that is energy efficient).
For example, say I start at one place and then 2 minutes later I'm 5km from the distance that I originally started at. At this point the GPS would detect the change in location and update the latitude and longitude on the device.
If anyone could provide some insight or code samples on how to do this, that'd be great!
Thanks
You can based your position attribute update on how far you are from the previous location, but you can't based GPS frequency update on that, simply because you need a location request to find out that you are far enough.
If you want an energy efficient solution, you can reduce the rate at which new update appear. You can also reduce the window duration in which you listen for position (position may be less accurate).
A lot of information can be found here, specially in Adjusting the model to save battery and data exchange and Deciding when to start listening for updates chapters
You can get the location change if you specify the distance you want to get updates in the requestLocationUpdate parameter.
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)
Here is example:
LocationManager yourLoc = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
yourLoc.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 2, onLocationChange);
Here you will receive location changes after every 2 meters you have travelled, irrespective of the time you spent at a particular location.
Hope that answers your question!!!
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 :)
I am receiving periodically location updates via GPS, the problem is the time until the first location update occurs - it is just to long. When the user is within a building, this time gets even worser.
Therefore I am looking for some strategies to improve the startup time (at the moment I don't use getLastKnownLocation but I will). I started reading A Deep Dive Into Location to get some ideas and have some thoughts now I would like to discuss with you.
At first the blog post mentioned above goes through each location provider on the device and queries for the getLastKnownLocation, but only considers them when they are not to old and within an allowed accuracy.
Here comes my first question: I would expect to have the network based location immediately available, so I would request a new network based location, then I would get getLastKnownLocation from the GPS-provider and if the last GPS-location is within the circle formed by the point network based location and radius accuracy then I would take the GPS location, regardless how old it is. What do you think?
After checking the last known location I will start the GPS position tracking and because I only need it every 2 seconds and 10m change, I would use
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2 * 1000, 10, this);
However I found a pattern (inside the presentation Being Epic: Best Practices for Android Development on slide 95 and 96 that at first he turns on coarse and fine locations (with 0,0 for time and distance changes) and then, when the first event is received, he switches to the really needed update frequency. So, does the first gps-update comes faster when the interval is set to 0?
In opposite to this pattern I would keep the coarse update until the first GPS update is received. What do you think?
Hope to get some interesting answers!
----------------Update----------------
I did some investigations: I turned on GPS and waited to get a fix. Then I turned GPS off and drove 50km (31 miles). Then I used the code from A Deep Dive Into Location to get all the getLastKnownLocation. I tried it twice, first with GPS turned off and second with GPS turned on, but without a fix:
1) with GPS turned off I got
- Provider: network, correct location with accuracy 680m
- Provider: passive (mProvider=network), same location as above, same time as above
- Provider: gps, location null
So I learned that when gps is turned off you get no getLastKnownLocation.
2) with GPS turned on I got
- Provider: network, correct location with accuracy 652m
- Provider: passive (mProvider=network), same location as above, same time as above
- Provider: gps, location as it was 2h earlier with accuracy 12m, time was also 2h earlier
Here I learned that old messages are not invalidated, even it is obvious that they are wrong.
In that case the algorithm works fine, because I moved in the time I turned the GPS off.
But what if I enter a house? In that case the 2h old GPS result would be very good, even it is outdated.
At the Google IO 2013 they showed in the session Beyond the Blue Dot: New Features in Android Location a new approach, see the video here.
The engineers at Google tried a lot of different strategies, the result is the "Fused location provider". Its quality is shown at 12:17 in the video.
Ketan Parmar has published a blog post how the fused location provider can be used in an example application.
Start up the location manager with the passive provider first
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, AlarmManager.INTERVAL_FIFTEEN_MINUTES, 75, this);
then once you get a response from that you can switch to your gps hardware.
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
I am trying to get the current location. For that I implement a LocationListener and register it for both the network and the GPS provider:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
I block then for 30 seconds and use the first location that gets passed into the listener's
onLocationChanged()
method with an accuracy of 100 meters or better.
Most of the time this works fine. If the phone is connected to some Wifi network, it takes just a second to get a correct location with an accuracy of about 50 meters. If there is no Wifi but GPS is enabled, it can of course take a while to get a location.
Sometimes however, when connected to a Wifi and getting the current location, some old (cached?) previous "Wifi" location is provided - it might be 15 minutes old and 15 kilometers away from the current location.
The problem is, that
location.getTime()
returns the current time - so it is impossible to know that the location is old.
I guess I have to implement a more elaborate solution - I would just like to know why these old "Wifi" locations have a current timestamp instead one from the time when it was originally retrieved.
This is a known issue which I have encountered and did some research on why this happens.
Here are my observations:
Usually this happens when the mobile network hand-off is happening after losing network connectivity which may not necessarily be significant enough for the user to realize.
Consider you are taking a tube train and you get in at station A and get down at station B, now when you get down at station B the network cell ID may/maynot still be of station A and of course it will do a hands-off and move to station B.
However if you call for getLocation is active before the hand-off you would get station A location which might be like 10 km and 15 mins back.
First understand how network location works:
Android has the cellId of the tower to which it is currently connected to and this id is then used by google to perform look-up and fetch approximate location information whose accuracy can range from 50 metres (one of the best) to a few thousand metres. If the cellId is incorrect as shown in the above example then you would receive wrong location.
There is not much you can do to avoid this except having a custom algorithm that can weed out this noise. Something like
if (location from network) {
if (speed obtained from the difference between previous and current location is greater than say 30 m/s) {
ignore this location as noise
} else {
location is correct
}
}
This is helpful:
A Deep Dive Into Location
and lastly the source code for that talk:
android-protips-location
I have been facing the same issues until I made some changes to my code.
What happened is that I was attaching the same LocationListener when requesting for both GPS and Network location updates and I was getting "weird" issues including getting old WIFI location updates with current time.
Here's my old code:
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, locationListener);
Apparently that is a rather "unsafe" thing to do (sorry, Android newbie here) and so I changed it to:
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, networkLocationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, gpsLocationListener);
Of course I had to define 2 separate onLocationChanged block of codes to handle the 2 listeners.
Well, it did solve my problem. I tested this on Gingerbread (API Level: 8). Not sure if it works for you.