How to get last location on Glass reliably?

醉酒当歌 提交于 2019-12-21 04:45:12

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!