问题
Method getLastLocation()
from LocationManager
often return null and it's quite tricky to select best provider. The documentation says:
Warning: Do not use the LocationManager.getBestProvider() method or the constants GPS_PROVIDER or NETWORK_PROVIDER to listen for location updates. Glass uses a dynamic set of providers and listening only to a single provider may cause your application to miss location updates.
How to get best last location?
回答1:
Because Glass uses dynamic set of providers, you need to get location from all of them and select the location with best accuracy:
public static Location getLastLocation(Context context) {
LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
List<String> providers = manager.getProviders(criteria, true);
List<Location> locations = new ArrayList<Location>();
for (String provider : providers) {
Location location = manager.getLastKnownLocation(provider);
if (location != null && location.getAccuracy()!=0.0) {
locations.add(location);
}
}
Collections.sort(locations, new Comparator<Location>() {
@Override
public int compare(Location location, Location location2) {
return (int) (location.getAccuracy() - location2.getAccuracy());
}
});
if (locations.size() > 0) {
return locations.get(0);
}
return null;
}
回答2:
Destil's answer above correctly handles the case where at least one provider returns a valid location for getLastKnownLocation()
.
However, I've also seen Glass return null
for getLastKnownLocation()
for all providers (in XE16 in particular).
In this case, your only option is to register a LocationListener and wait for a new location update.
For example, in context of getting a location when creating a new Activity, it would look like the following:
public class MyActivity extends Activity implements LocationListener {
...
LocationManager mLocationManager;
Location mLastKnownLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Activity setup
...
// Use Destil's answer to get last known location, using all providers
mLastKnownLocation = getLastLocation(this);
if (mLastKnownLocation != null) {
// Do something with location
doSomethingWithLocation(mLastKnownLocation);
} else {
// All providers returned null - start a LocationListener to force a refresh of location
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
List<String> providers = mLocationManager.getProviders(true);
for (Iterator<String> i = providers.iterator(); i.hasNext(); ) {
mLocationManager.requestLocationUpdates(i.next(), 0, 0, this);
}
}
...
}
...
}
You'll then need to handle the LocationListener
callbacks:
@Override
public void onLocationChanged(Location location) {
if (mLastKnownLocation == null) {
// At least one location should be available now
// Use Destil's answer to get last known location again, using all providers
mLastKnownLocation = getLastLocation(this);
if (mLastKnownLocation == null) {
// This shouldn't happen if LocationManager is saving locations correctly, but if it does, use the location that was just passed in
mLastKnownLocation = location;
}
// Stop listening for updates
mLocationManager.removeUpdates(this);
// Do something with location
doSomethingWithLocation(mLastKnownLocation);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {}
It can be a little tricky to change to the asynchronous model to avoid blocking the UI thread while waiting for the update, and it may require moving some of your app logic around.
回答3:
The code in the answer should be adjusted to handle an accuracy of "0.0" which represents "NO Accuracy" known!
Here is an alternative that includes this adjustment
public static Location getLastLocation(Context context) {
Location result = null;
LocationManager locationManager;
Criteria locationCriteria;
List<String> providers;
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationCriteria = new Criteria();
locationCriteria.setAccuracy(Criteria.NO_REQUIREMENT);
providers = locationManager.getProviders(locationCriteria, true);
// Note that providers = locatoinManager.getAllProviders(); is not used because the
// list might contain disabled providers or providers that are not allowed to be called.
//Note that getAccuracy can return 0, indicating that there is no known accuracy.
for (String provider : providers) {
Location location = locationManager.getLastKnownLocation(provider);
if (result == null) {
result = location;
}
else if (result.getAccuracy() == 0.0) {
if (location.getAccuracy() != 0.0) {
result = location;
break;
} else {
if (result.getAccuracy() > location.getAccuracy()) {
result = location;
}
}
}
}
return result;
}
来源:https://stackoverflow.com/questions/21364663/how-to-get-last-location-on-glass-reliably