Reputation: 8156
I am trying to get the current user's location. I have tried to refactor my code to get better results but I just keep getting ridiculous locations in regard to the accuracy, it is between 900-600 meters.
How can I get a better result, so as to force it to an accuracy within 50m?
Here is my code:
package com.agam.mapslocation;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
public class MapsActivity extends Activity {
private static final int ONE_MINUTE = 1000 * 60 * 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
final LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
final EditText et = (EditText) findViewById(R.id.editText1);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location l) {
// Called when a new location is found by the network location
// provider.
Location gps = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location net = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Location bestLocation = null;
bestLocation = isBetterLocation(gps, net);
bestLocation = isBetterLocation(bestLocation, l);
if(bestLocation!=null)
displayLocation(et, bestLocation);
}
public void onStatusChanged(String provider, int status,
Bundle extras) {
}
public void onProviderEnabled(String provider) {
if (provider.equals(LocationManager.GPS_PROVIDER)) {
et.setText("GPS ON!");
}
}
public void onProviderDisabled(String provider) {
}
};
// Register the listener with the Location Manager to receive location
// updates
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, locationListener);
}
public static void displayLocation(View v, Location l) {
((EditText) v).setText(String.format(
"Long:%s,\nLat:%s,\nAccu:%s,\nTime ago:%s,\nProvider:%s",
l.getLongitude(), l.getLatitude(), l.getAccuracy(),
new java.util.Date().getTime() - l.getTime(), l.getProvider()));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_maps, menu);
return true;
}
/**
* Determines whether one Location reading is better than the current
* Location fix
*
* @param location
* The new Location that you want to evaluate
* @param currentBestLocation
* The current Location fix, to which you want to compare the new
* one
*/
protected Location isBetterLocation(Location location,
Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return location;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > ONE_MINUTE;
boolean isSignificantlyOlder = timeDelta < -ONE_MINUTE;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return location;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return currentBestLocation;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and
// accuracy
if (isMoreAccurate) {
return location;
} else if (isNewer && !isLessAccurate) {
return location;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
return location;
}
return currentBestLocation;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
}
Note: I am putting emphasis on static location, e.g. not moving because it may help with the answers.
Upvotes: 3
Views: 6908
Reputation: 19651
There are two factors you need to consider to obtain an accurate location:
The code, eg
The device
These are discussed below.
Code
Make sure you have followed the guidance from Android Developer (Thanks Bill Gary)
But remember that the code will work only if the device itself has the requisite HW and configuration - see below.
Device
To understand what is going wrong with your location fix, it really helps to understand how your device locates itself. Location is obtained by several technologies:
GPS chipset
MACs visible on WiFi (by querying a central DB such as Google's)
The location of the cell-phone mast you are using (Network Provider)
When you ask for a location fix (excluding the last, cached one), a good GPS location provider actually looks at a lot more than just GPS:
It starts GPS tracking if the GPS chipset is enabled
It starts a scan of the Wifi environment, if WiFi is enabled
Often you can see these effects on Google Maps, for example: when you start it you see a large approximate location (cell tower) from the Network Provider, a few seconds later it zooms in on an area with a greater degree of accuracy (WiFi), and finally you may get a GPS fix.
It's always worth:
EDIT
From the basic results you're getting, you seem to have only results from the Network Provider. So, do:
Upvotes: 3
Reputation: 10518
You should set locationListeners to all available location providers as soon as possible and wait. Setting listeners ask providers to give you all data they have immediately (minTime=0, minDistance=0). Use getLastKnownLocation as first location approximation. During time you will start getting some location data from different providers. You should manually choose the most suitable for your case (most precise, I suppose). Keep waiting as long as you can (The more you wait the better location values you will probably get). When waiting time is over take the best location you've been given and start using it. You can continue listen for location updates and improve location estimation if System will be able to give you a better value.
Upvotes: 0