Saturday, February 11, 2012

Easy and efficient way to get latest location

If you create an application with the use of location based services than you should be aware how critical the time spent in obtaining the coordinates and save battery life. So, instead of requesting location update every time we need it, lets just check what we already have and choose most accurate result within the acceptable time limit. And only in case we don't get any result we will force location update...
public Location LastBestLocation(int minDistance, long minTime) {  
  Location result = null;
  float bestAccuracy = Float.MAX_VALUE;
  long bestTime = Long.MAX_VALUE;

  Context context = getApplicationContext();
  LocationListener locationListener = locationListener;
  LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
  Criteria criteria = new Criteria();
  criteria.setAccuracy(Criteria.ACCURACY_FINE);
  criteria.setPowerRequirement(Criteria.POWER_LOW);

  List matchingProviders = locationManager.getAllProviders();
  for (String provider: matchingProviders) {
    Location location = locationManager.getLastKnownLocation(provider);   
    if (location != null) {
      float accuracy = location.getAccuracy();
      long time = location.getTime();
      if ((time < minTime && accuracy < bestAccuracy)) {
        result = location;
        bestAccuracy = accuracy;
        bestTime = time;
      } else if (time > minTime && bestAccuracy == Float.MAX_VALUE && time < bestTime){
        result = location;
        bestTime = time;
      }
    } 
  }
  
  // check if result is within limits (time and accuracy)
  if (locationListener != null && (bestTime > minTime || bestAccuracy > minDistance)) { 
    String provider = locationManager.getBestProvider(criteria, true);
    if (provider != null) {

      // if there's no result - request location update
      locationManager.requestLocationUpdates(provider, 0, 0, locationListener, context.getMainLooper());
      
      // if GPS Provider is available than register it for location update, 
      // but only for 30 second (usually it's enough time to get fix with clear sky)
      // remove GPS listener if it takes longer than 30 seconds to get GPS fix
      if (provider.equalsIgnoreCase(LocationManager.GPS_PROVIDER)) {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable(){
          @Override
          public void run() { 
            locationManager.removeUpdates(locationListener);              
          }
        }, 30000L);
      }
    }
  }
  return result;
}


protected LocationListener locationListener = new LocationListener() {
  @Override
  public void onLocationChanged(Location location) {
    locationManager.removeUpdates(locationListener);
  }
  
  @Override public void onProviderDisabled(String provider) {}
  @Override public void onProviderEnabled(String provider) {}
  @Override public void onStatusChanged(String provider, int status, Bundle extras) {}
};

No comments:

Post a Comment