I have used the code below and everything is working fine except that onLocationChanged is called even if I am sitting at the same location .
I thought it should be called only when I am moving right ?
I only want to get the location after I have moved a certain distance.
Please help me out.
Thanks in advance.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
this);
}
#Override
public void onLocationChanged(Location location) {
Toast.makeText(this, "Working!", Toast.LENGTH_SHORT).show();
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
String Text = "Latitud = " + lat + "\nLongitud = " +
lng;
Toast.makeText(getBaseContext(),Text,Toast.LENGTH_SHORT).show();
}
}
You're requesting location updates at the shortest possible intervals/distances
locationMgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
this);
This is what the documentation says about those parameters
" The location update interval can be controlled using the minTime parameter. The elapsed time between location updates will never be less than minTime, although it can be more depending on the Location Provider implementation and the update interval requested by other applications. "
The minDistance parameter can also be used to control the frequency of location updates. If it is greater than 0 then the location provider will only send your application an update when the location has changed by at least minDistance meters, AND at least minTime milliseconds have passed. However 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.
I personally use a minTime of 10 seconds and 10 meters for my app
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000,
10, locationListener);
Network location is not as precise as you would think it is. Therefore the result returned by the sensors can fluctuate. This is even more true when you consider that GPS signal weakens if you don't have direct line of sight with the satellites, and the number of visible satellites also has effect on the precision. This gets even worse when you start using the network provider, where the position is calculated by triangulation of the signal strength of cell towers, and the number and SSIDs of visible wireless network. Since these can fluctuate quite a lot, the precision suffers greatly. There are bunch of averaging algorithms, and heuristics employed to minimize such fluctuations, but ultimately nothing can stabilize it to be as good as you expect it to be.
A simple averaging and variation filtering can help you. Adding a correction based on the device accelerometer can also help a lot, but it will make your code more complex.
Related
I have the following code in main activity:
LocationManager mlocMan = (LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE);
if (mlocMan.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
LocationListener mlocListener = new LocationManagerHelper(...);
mlocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,mlocListener);
}
In the location listener I have this: (theAccuracy was initialized to -1)
if (theAccuracy == -1 || theAccuracy > loc.getAccuracy()) {
theAccuracy = Math.round(loc.getAccuracy());
latitude = loc.getLatitude();
longitude = loc.getLongitude();
}
updateTimes++;
if (updateTimes == 3) {
mLocMan.removeUpdates(this);
updateTimes = 0;
//get address for location
theAccuracy = -1;
}
Meaning, after 3 location updates from the GPS, take the best accurate location and get its address. On the emulator I get fixed accuracy of 20m (I send long/lat using DDMS) but that's not real life so I tried with my device and while the very first time (3 requests) gave me the exact address (on the spot) with 40m accuracy, the next ones were sometimes more accurate but the address was nearby. The best accuracy I got was 29m (happened once) most of the times it's above 30. Is this a problem of my GPS (LG G3) or is there any other idea that can make things more accurate after 3-4-5 requests?
A few reasons:
Your emulator doesn't have actual gps hardware, so it's probably using your ip address, so that's why it seems fixed.
GPS hardware on your phone has to warm up a bit. Set the frequency of polling up for a bit (1 update a second, or half-second), and let it run for a few seconds, before taking measurements that count.
The location manager supports both hardware and network lookups (wifi / celltowers). Not sure how to set provider to just your phone's hardware, but if you use the googlePlayServices gps client (LocationClient), it's quite simple:
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) this);
You're probably testing at your computer in doors. Buildings definitely effect gps accuracy.
I am building a GPS Android application which gets the nearest places based on the user's current location.
This is what my application does:
Check if GPS or Network is available
If neither is available then don't do anything. Else, we first check for GPS if it's there, if not then we check for Network.
After using one of them, we get the current location and then send it off to the server.
Once we retrieve data from the server and update the UI, we stop listening for further location updates. Once is enough, until they press the refresh button which starts this again.
What I hope to do:
If GPS or network fails to retrieve a location, for example, 2 minutes, then we switch providers. We don't want the user to wait too long.
It would also be nice to be able to use both providers and then get the most accurate from that. I've taken a look at http://developer.android.com/guide/topics/location/strategies.html and I saw the isBetterLocation method. How would I integrate this method in my application? I'm having trouble understand how, where and when it should be called. I assume that the isBetterLocation() requires me to call both Network and GPS at the same time. It would be nice for my application to listen to both for accuracy. How do I do this? What if one of them isn't available?
Here's parts of my code:
if(!GPSEnabled && !networkEnabled)
{
Toast.makeText(this, "Error: This application requires a GPS or network connection",
Toast.LENGTH_SHORT).show();
}
else
{
if(GPSEnabled)
{
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
else if(networkEnabled)
{
System.out.println("Getting updates from network provider");
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
}
This is the onLocationChanged method. I get the lat/lng values and then send them off to my server and then do appropriate stuff with it.
public void onLocationChanged(Location location)
{
//Get coordinates
double lat = (location.getLatitude());
double lng = (location.getLongitude());
Log.d("MainActivity", "got location: " + lat + ": " + lng);
//get nearest locations
new GetLocations().execute(SharedVariables.root + SharedVariables.locationsController + SharedVariables.getNearestMethod + lat + "/" + lng);
// Zoom in, animating the camera after the markers have been placed
map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
System.out.println("lat = " + lat + ", lng = " + lng);
//Stop listening for updates. We only want to do this once.
locManager.removeUpdates(this);
}
Either using GPS or the network, you can't drastically reduce the eventual waiting time to get your location.
Both of these location methods have their disadvantages and advantages:
GPS usually takes a longer time to know your location, because finding and calibrating GPS satellites is a tremendous task (finding at least 3 correctly-aligned satellites is required). On top of that, add the eventual obstructing objects/environment blocking the signals. Unless you enable GPS before/when your app starts, wait is mandatory. On the other side, you get a fine-grained location.
If you only need a rough location, using the network is a solution: it returns data in a few seconds. However the precision of the location varies depending on the available/used networks; I don't have any practical examples, but I guess the precision can greatly vary. GPS will ALWAYS have a better-grained location than network.
Understand there is no predefined choice. Anything depends on what your app does with this data.
Use GPS if available, while making the location request to the network, and fall back to network if there is no GPS device. Then take either:
the first-coming result if you just need a location
the preferred result if you want the most precise data
If GPS or network fails to retrieve a location, for example, 2 minutes, then we switch providers. We don't want the user to wait too long.
In both cases, do not make a fallback timer: you'll just lengthen the waiting time in the case where the first provider fails; so do both request at the same time, unless the android API does not permit asynchronous location requests.
I am exploring the possibilities of using the GPS for VR gaming. Both frequency and accuracy are very low with my current test build.
In manifest I have
<uses-permission android:name="android.permission.LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And I instance location manager like
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, this);
I then use the distanceBetween function to get the bearing and distance
public void onLocationChanged(Location location) {
if(lastLocation != null) {
Location.distanceBetween(lastLocation.getLatitude(), lastLocation.getLongitude(), location.getLatitude(), location.getLongitude(), distanceBetween);
newGpsDataToSend = true;
if(debug)
debugListener.debugGPS(distanceBetween);
releaseSendThread();
}
lastLocation = location;
}
The frequency is below 1hz (5-10hz should be possible right?) and the bearing and distance is very jumpy.
Am I doing something wrong in the code? I do not care about battery consumption etc, I jsut want the fastest most reliably data I can get from the phone.
Complete source
https://github.com/AndersMalmgren/FreePIE/blob/VRWalk/Lib/Android/FreePIE%20Android%20IMU/src/com/freepie/android/imu/UdpSenderTask.java#L120
For hight sampling frequencies (counting 1 Hz as high for GPS sampling) you will get GPS readings where the distances between locations is less than the GPS accurracy. Therefore bearing an and distance are jumpy as observed.
To get a better bearing lower the sampling frequency or process the data by filtering or computing an average.
E.g., for a flight logging application I am sampling about every 2 to 5 seconds and I am computing the average of the last 5 altitude readings to compute vertical speed.
I'm testing an Android app that records the location (lat/long/alt). I'm running the app on a Samsung GTS5830 phone running Android 2.2.1
I read here and there that GPS altitude is often incorrect due to the earth not being perfectly spherical. At my location, for example, the geoid's height is 52 meters.
My understanding is that this height would be substracted from a "pure" GPS altitude. This would make sense for my location as:
- altitude from GPS phone: 535 m
- geoid altitude: 52 m
- altitude from phone's GPS minus geoid height: 482m
- correct atlitude: 478 m
482 is close enough to the real thing for me to track elevation when hiking
Is the above formula of the GPS height minus the geoid's height correct?
Am I correct to assume that android is not factoring in the geoid's height when returning the GPS altitude?
If the above is true, does it hold for all versions of Android?
Here is the code I use to obtain the GPS coordinates:
public class HelloAndroid extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d("main", "onCreate");
setupGps();
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
LocationListener locationListener;
LocationManager lm;
void setupGps() {
Log.d("gps", "Setting up GPS...");
locationListener = new MyLocationListener();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 20000, 5,
locationListener);
Log.d("gps",
"GPS supports altitude: "
+ lm.getProvider(LocationManager.GPS_PROVIDER)
.supportsAltitude());
Log.d("gps", "Finished setting up GPS.");
}
static class MyLocationListener implements LocationListener {
public void onLocationChanged(Location location) {
Log.d("gps", "long: " + location.getLongitude() + ", lat: "
+ location.getLatitude() + ", alt: "
+ location.getAltitude());
}
}
}
The answers to all three of your questions are yes.
The altitude you get from GPS is the height above the WGS84 ellipsoid in metres, which is an approximation of the earth's surface. I know that because I've been developing Android software to use it.
A correction has to be applied to convert the figure to height above mean sea level, or altitude as it is usually known. Note that this may differ from the altitude reported by an altimeter set to the current pressure at mean sea level because an altimeter actually measures air pressure, but air pressure is not just a function of height; it is also a function of air density and temperature, so an altimeter shows an approximation. This effect is not seen with GPS.
The Earth Gravitational Model 2008 (EGM2008) maps the difference in mean sea level with the ellipsoid as a function of longitude and latitude. Details are here:
http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/egm08_wgs84.html
A less accurate model that uses less data called EGM96 is also available. Google both of these to understand these better.
It's not quite that simple -- the Android API has either changed or has bugs. I have two Android devices -- a 'generic' phone (Android 2.3.6) and a Nexus 7 (Android 4.x).
On the phone, getAltitude() gives an answer consistent with my actual altitude AMSL (i.e., corrected for geoid). On the Nexus 7, the altitude returned is uncorrected. The documentation for the API does not specify which is returned -- so in some sense both are 'correct'.
Both devices seem to have decent GPS modules -- the $GPGGA NMEA message shows both the correct altitute and the geoid correction. So it looks as though one has to parse the messages oneself to get the correct altitude, and the getAltitude() method is untrustworthy.
Errors in the altitude may well not be down to the GPS and geoid altitude separation.
The altitude value returned by any GPS receiver is always the least accurate value. I have often seen my office building report that it is moving in altitude between -200 and +750 metres. One fundamental reason is that it is impossible to get an even spread of satellites in the altitude direction; they are always going to be above you, and if there is any obscuration of the sky at low elevations, they will be located in a cone above you. In the X and Y directions there will always, assuming a good sky view, be satellites spread left and right; in front and behind the receiver. This spread enhances the accuracy of the position solution.
I am writing an application that shows your location in a google map...
so far, so good... It does shows my location correctly
The problem is that this gps is not updated if I am moving (or it does, but only after some time)
Does anybody know how to do this in a way like the native google maps (for android) does?
This is, if you click on 'my location' it shows a flashing blue point that changes as you move...
This is my code:
//Initializing the listeners
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 35000, 10, networkLocationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 35000, 10, gpsLocationListener);
//and now, in both 'networkLocationListener' and 'gpsLocationListener'
//I overwrite the method 'onLocationChanged':
#Override
public void onLocationChanged(Location location) {
Log.i("test", "New network location: "+location.getLatitude()+
" , "+location.getLongitude());
myLongitude= location.getLongitude();
myLatitude= location.getLatitude();
}
//and the variables myLongitude and myLatitude are the only ones that I need to display my
//position in the map...
Does anybody knows if I am missing something?
The method call you are using is requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener), and you're telling it to only give you updates every 35000ms or every 35 seconds. Try lowering that number to whatever suits you. A lower number will mean more battery usage though.
If you want an indicator on a MapView, look into MyLocationOverlay.
You wouldn't want to leave it like this forever, but it might be worth setting the minTime and minDistance values to zero if you haven't given that a shot yet.
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsLocationListener);
If minTime is greater than 0, the LocationManager could potentially rest for minTime milliseconds between location updates to conserve power. If minDistance is greater than 0, a location will only be broadcasted if the device moves by minDistance meters. To obtain notifications as frequently as possible, set both parameters to 0.
-requestLocationUpdates Reference