¿Cuál es la forma más simple y sólida de obtener la ubicación actual del usuario en Android?

La API de LocationManager en Android parece ser un poco difícil de usar para una aplicación que solo necesita una aproximación ocasional y aproximada de la ubicación del usuario.

La aplicación en la que estoy trabajando no es realmente una aplicación de ubicación per se, pero sí necesita obtener la ubicación del usuario para mostrar una lista de negocios cercanos. No necesita preocuparse si el usuario se está moviendo o algo por el estilo.

Esto es lo que me gustaría hacer:

  1. Muestra al usuario una lista de ubicaciones cercanas.
  2. Precargue la ubicación del usuario para que, cuando lo necesite en la Activity X, esté disponible.
  3. No me preocupa particularmente la precisión o la frecuencia de la actualización. Solo agarrar un lugar es suficiente siempre y cuando no esté lejos. Tal vez si quiero ser elegante, actualizaré la ubicación una vez cada pocos minutos, pero no es una gran prioridad.
  4. Trabaja para cualquier dispositivo, siempre que tenga un GPS o un proveedor de ubicación de red.

Parece que no debería ser tan difícil, pero me parece que tengo que girar dos proveedores de ubicación diferentes (GPS y NETWORK) y administrar el ciclo de vida de cada uno. No solo eso, sino que tengo que duplicar el mismo código en múltiples actividades para satisfacer el # 2. Intenté utilizar getBestProvider() en el pasado para reducir la solución a solo usar un proveedor de ubicación, pero parece que solo le brinda el mejor proveedor “teórico” en lugar del proveedor que realmente le dará los mejores resultados.

¿Hay una manera más simple de lograr esto?

Esto es lo que hago:

  1. Antes que nada, verifico qué proveedores están habilitados. Algunos pueden estar deshabilitados en el dispositivo, algunos pueden estar deshabilitados en el manifiesto de la aplicación.
  2. Si hay algún proveedor disponible, inicio escuchas de ubicación y temporizador de tiempo de espera. Son 20 segundos en mi ejemplo, puede que no sea suficiente para el GPS, así que puedes agrandarlo.
  3. Si recibo una actualización del escucha de ubicación, uso el valor proporcionado. Detengo a los oyentes y el temporizador.
  4. Si no obtengo ninguna actualización y el tiempo transcurre, debo usar los últimos valores conocidos.
  5. Obtengo los últimos valores conocidos de los proveedores disponibles y elijo los más recientes.

Así es como uso mi clase:

 LocationResult locationResult = new LocationResult(){ @Override public void gotLocation(Location location){ //Got the location! } }; MyLocation myLocation = new MyLocation(); myLocation.getLocation(this, locationResult); 

Y aquí está la clase MyLocation:

 import java.util.Timer; import java.util.TimerTask; import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; public class MyLocation { Timer timer1; LocationManager lm; LocationResult locationResult; boolean gps_enabled=false; boolean network_enabled=false; public boolean getLocation(Context context, LocationResult result) { //I use LocationResult callback class to pass location value from MyLocation to user code. locationResult=result; if(lm==null) lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); //exceptions will be thrown if provider is not permitted. try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){} try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){} //don't start listeners if no provider is enabled if(!gps_enabled && !network_enabled) return false; if(gps_enabled) lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps); if(network_enabled) lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork); timer1=new Timer(); timer1.schedule(new GetLastLocation(), 20000); return true; } LocationListener locationListenerGps = new LocationListener() { public void onLocationChanged(Location location) { timer1.cancel(); locationResult.gotLocation(location); lm.removeUpdates(this); lm.removeUpdates(locationListenerNetwork); } public void onProviderDisabled(String provider) {} public void onProviderEnabled(String provider) {} public void onStatusChanged(String provider, int status, Bundle extras) {} }; LocationListener locationListenerNetwork = new LocationListener() { public void onLocationChanged(Location location) { timer1.cancel(); locationResult.gotLocation(location); lm.removeUpdates(this); lm.removeUpdates(locationListenerGps); } public void onProviderDisabled(String provider) {} public void onProviderEnabled(String provider) {} public void onStatusChanged(String provider, int status, Bundle extras) {} }; class GetLastLocation extends TimerTask { @Override public void run() { lm.removeUpdates(locationListenerGps); lm.removeUpdates(locationListenerNetwork); Location net_loc=null, gps_loc=null; if(gps_enabled) gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); if(network_enabled) net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); //if there are both values use the latest one if(gps_loc!=null && net_loc!=null){ if(gps_loc.getTime()>net_loc.getTime()) locationResult.gotLocation(gps_loc); else locationResult.gotLocation(net_loc); return; } if(gps_loc!=null){ locationResult.gotLocation(gps_loc); return; } if(net_loc!=null){ locationResult.gotLocation(net_loc); return; } locationResult.gotLocation(null); } } public static abstract class LocationResult{ public abstract void gotLocation(Location location); } } 

Alguien también puede querer modificar mi lógica. Por ejemplo, si recibe una actualización del proveedor de la red, no detenga a los oyentes, sino que continúe esperando. El GPS proporciona datos más precisos por lo que vale la pena esperar. Si transcurre el tiempo del temporizador y tiene una actualización de la red pero no del GPS, puede usar el valor proporcionado por la red.

Un enfoque más es utilizar LocationClient http://developer.android.com/training/location/retrieve-current.html . Pero requiere la aplicación Google Play Services para instalarse en el dispositivo del usuario.

Después de buscar la mejor implementación para obtener la mejor ubicación precisa para el usuario, logré combinar los mejores métodos y crear la siguiente clase:

 /** * Retrieve accurate location from GPS or network services. * * * Class usage example: * * public void onCreate(Bundle savedInstanceState) { * ... * my_location = new MyLocation(); * my_location.init(main.this, locationResult); * } * * * public LocationResult locationResult = new LocationResult(){ * @Override * public void gotLocation(final Location location){ * // do something * location.getLongitude(); * location.getLatitude(); * } * }; */ class MyLocation{ /** * If GPS is enabled. * Use minimal connected satellites count. */ private static final int min_gps_sat_count = 5; /** * Iteration step time. */ private static final int iteration_timeout_step = 500; LocationResult locationResult; private Location bestLocation = null; private Handler handler = new Handler(); private LocationManager myLocationManager; public Context context; private boolean gps_enabled = false; private int counts = 0; private int sat_count = 0; private Runnable showTime = new Runnable() { public void run() { boolean stop = false; counts++; System.println("counts=" + counts); //if timeout (1 min) exceeded, stop tying if(counts > 120){ stop = true; } //update last best location bestLocation = getLocation(context); //if location is not ready or don`t exists, try again if(bestLocation == null && gps_enabled){ System.println("BestLocation not ready, continue to wait"); handler.postDelayed(this, iteration_timeout_step); }else{ //if best location is known, calculate if we need to continue to look for better location //if gps is enabled and min satellites count has not been connected or min check count is smaller then 4 (2 sec) if(stop == false && !needToStop()){ System.println("Connected " + sat_count + " sattelites. continue waiting.."); handler.postDelayed(this, iteration_timeout_step); }else{ System.println("#########################################"); System.println("BestLocation finded return result to main. sat_count=" + sat_count); System.println("#########################################"); // removing all updates and listeners myLocationManager.removeUpdates(gpsLocationListener); myLocationManager.removeUpdates(networkLocationListener); myLocationManager.removeGpsStatusListener(gpsStatusListener); sat_count = 0; // send best location to locationResult locationResult.gotLocation(bestLocation); } } } }; /** * Determine if continue to try to find best location */ private Boolean needToStop(){ if(!gps_enabled){ return true; } else if(counts < = 4){ return false; } if(sat_count < min_gps_sat_count){ //if 20-25 sec and 3 satellites found then stop if(counts >= 40 && sat_count >= 3){ return true; } return false; } } return true; } /** * Best location abstract result class */ public static abstract class LocationResult{ public abstract void gotLocation(Location location); } /** * Initialize starting values and starting best location listeners * * @param Context ctx * @param LocationResult result */ public void init(Context ctx, LocationResult result){ context = ctx; locationResult = result; myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); gps_enabled = (Boolean) myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); bestLocation = null; counts = 0; // turning on location updates myLocationManager.requestLocationUpdates("network", 0, 0, networkLocationListener); myLocationManager.requestLocationUpdates("gps", 0, 0, gpsLocationListener); myLocationManager.addGpsStatusListener(gpsStatusListener); // starting best location finder loop handler.postDelayed(showTime, iteration_timeout_step); } /** * GpsStatus listener. OnChainged counts connected satellites count. */ public final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() { public void onGpsStatusChanged(int event) { if(event == GpsStatus.GPS_EVENT_SATELLITE_STATUS){ try { // Check number of satellites in list to determine fix state GpsStatus status = myLocationManager.getGpsStatus(null); Iterablesatellites = status.getSatellites(); sat_count = 0; IteratorsatI = satellites.iterator(); while(satI.hasNext()) { GpsSatellite satellite = satI.next(); System.println("Satellite: snr=" + satellite.getSnr() + ", elevation=" + satellite.getElevation()); sat_count++; } } catch (Exception e) { e.printStackTrace(); sat_count = min_gps_sat_count + 1; } System.println("#### sat_count = " + sat_count); } } }; /** * Gps location listener. */ public final LocationListener gpsLocationListener = new LocationListener(){ @Override public void onLocationChanged(Location location){ } public void onProviderDisabled(String provider){} public void onProviderEnabled(String provider){} public void onStatusChanged(String provider, int status, Bundle extras){} }; /** * Network location listener. */ public final LocationListener networkLocationListener = new LocationListener(){ @Override public void onLocationChanged(Location location){ } public void onProviderDisabled(String provider){} public void onProviderEnabled(String provider){} public void onStatusChanged(String provider, int status, Bundle extras){} }; /** * Returns best location using LocationManager.getBestProvider() * * @param context * @return Location|null */ public static Location getLocation(Context context){ System.println("getLocation()"); // fetch last known location and update it try { LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); String strLocationProvider = lm.getBestProvider(criteria, true); System.println("strLocationProvider=" + strLocationProvider); Location location = lm.getLastKnownLocation(strLocationProvider); if(location != null){ return location; } return null; } catch (Exception e) { e.printStackTrace(); return null; } } } 

Esta clase intenta conectarse a los satélites min_gps_sat_count si el GPS está habilitado. Else devuelve la LocationManager.getBestProvider() . Verifica el código!

Con la solución de Fedor, he experimentado una ejecución múltiple de la callback gotLocation . Parece que se debe a una condición de carrera en el método LocationListener.onLocationChanged reemplazado, cuando el método getLocation es ‘suficientemente largo’ . No estoy seguro, pero supongo que removeUpdates evita el enqueueing de nuevos mensajes en la cola de Looper, pero no elimina los que ya están en cola pero que aún no se han consumido. De ahí la condición de carrera.

Para reducir la probabilidad de este comportamiento incorrecto, es posible llamar a removeUpdates antes de activar el evento onLocationChanged, pero todavía tenemos la condición de carrera.

La mejor solución que encontré es reemplazar requestLocationUpdates con requestSingleUpdate .

Esta es mi versión, basada en la solución de Fedor, usando un controlador para enviar un mensaje al hilo del looper:

 public class LocationResolver { private Timer timer; private LocationManager locationManager; private LocationResult locationResult; private boolean gpsEnabled = false; private boolean networkEnabled = false; private Handler locationTimeoutHandler; private final Callback locationTimeoutCallback = new Callback() { public boolean handleMessage(Message msg) { locationTimeoutFunc(); return true; } private void locationTimeoutFunc() { locationManager.removeUpdates(locationListenerGps); locationManager.removeUpdates(locationListenerNetwork); Location networkLocation = null, gpsLocation = null; if (gpsEnabled) gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (networkEnabled) networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); // if there are both values use the latest one if (gpsLocation != null && networkLocation != null) { if (gpsLocation.getTime() > networkLocation.getTime()) locationResult.gotLocation(gpsLocation); else locationResult.gotLocation(networkLocation); return; } if (gpsLocation != null) { locationResult.gotLocation(gpsLocation); return; } if (networkLocation != null) { locationResult.gotLocation(networkLocation); return; } locationResult.gotLocation(null); } }; private final LocationListener locationListenerGps = new LocationListener() { public void onLocationChanged(Location location) { timer.cancel(); locationResult.gotLocation(location); locationManager.removeUpdates(this); locationManager.removeUpdates(locationListenerNetwork); } public void onProviderDisabled(String provider) { } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider, int status, Bundle extras) { } }; private final LocationListener locationListenerNetwork = new LocationListener() { public void onLocationChanged(Location location) { timer.cancel(); locationResult.gotLocation(location); locationManager.removeUpdates(this); locationManager.removeUpdates(locationListenerGps); } public void onProviderDisabled(String provider) { } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider, int status, Bundle extras) { } }; public void prepare() { locationTimeoutHandler = new Handler(locationTimeoutCallback); } public synchronized boolean getLocation(Context context, LocationResult result, int maxMillisToWait) { locationResult = result; if (locationManager == null) locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); // exceptions will be thrown if provider is not permitted. try { gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); } catch (Exception ex) { } try { networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } catch (Exception ex) { } // don't start listeners if no provider is enabled if (!gpsEnabled && !networkEnabled) return false; if (gpsEnabled) locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListenerGps, Looper.myLooper()); //locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps); if (networkEnabled) locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, locationListenerNetwork, Looper.myLooper()); //locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork); timer = new Timer(); timer.schedule(new GetLastLocationTask(), maxMillisToWait); return true; } private class GetLastLocationTask extends TimerTask { @Override public void run() { locationTimeoutHandler.sendEmptyMessage(0); } } public static abstract class LocationResult { public abstract void gotLocation(Location location); } } 

Uso esta clase desde un hilo de looper personalizado, como el siguiente:

 public class LocationGetter { private final Context context; private Location location = null; private final Object gotLocationLock = new Object(); private final LocationResult locationResult = new LocationResult() { @Override public void gotLocation(Location location) { synchronized (gotLocationLock) { LocationGetter.this.location = location; gotLocationLock.notifyAll(); Looper.myLooper().quit(); } } }; public LocationGetter(Context context) { if (context == null) throw new IllegalArgumentException("context == null"); this.context = context; } public synchronized Coordinates getLocation(int maxWaitingTime, int updateTimeout) { try { final int updateTimeoutPar = updateTimeout; synchronized (gotLocationLock) { new Thread() { public void run() { Looper.prepare(); LocationResolver locationResolver = new LocationResolver(); locationResolver.prepare(); locationResolver.getLocation(context, locationResult, updateTimeoutPar); Looper.loop(); } }.start(); gotLocationLock.wait(maxWaitingTime); } } catch (InterruptedException e1) { e1.printStackTrace(); } if (location != null) coordinates = new Coordinates(location.getLatitude(), location.getLongitude()); else coordinates = Coordinates.UNDEFINED; return coordinates; } } 

donde Coordenadas es una clase simple con dos propiedades: latitud y longitud.

He creado una pequeña aplicación con descripción paso a paso para obtener las coordenadas GPS de las ubicaciones actuales.

enter image description here

Complete el código fuente del ejemplo en la siguiente URL:


Obtener coordenadas de ubicación actual, nombre de la ciudad – en Android


Vea cómo funciona:

  • Todo lo que tenemos que hacer es agregar este permiso en el archivo de manifiesto

       
  • y crea una instancia de LocationManager como esta

     LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
  • Comprobar GPS está habilitado o no

  • luego implementar LocationListener y obtener coordenadas

     LocationListener locationListener = new MyLocationListener(); locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000, 10, locationListener); 
  • aquí está el código de muestra para hacer


 /*----------Listener class to get coordinates ------------- */ private class MyLocationListener implements LocationListener { @Override public void onLocationChanged(Location loc) { editLocation.setText(""); pb.setVisibility(View.INVISIBLE); Toast.makeText( getBaseContext(), "Location changed: Lat: " + loc.getLatitude() + " Lng: " + loc.getLongitude(), Toast.LENGTH_SHORT).show(); String longitude = "Longitude: " + loc.getLongitude(); Log.v(TAG, longitude); String latitude = "Latitude: " + loc.getLatitude(); Log.v(TAG, latitude); /*-------to get City-Name from coordinates -------- */ String cityName = null; Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault()); List
addresses; try { addresses = gcd.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1); if (addresses.size() > 0) System.out.println(addresses.get(0).getLocality()); cityName = addresses.get(0).getLocality(); } catch (IOException e) { e.printStackTrace(); } String s = longitude + "\n" + latitude + "\n\nMy Current City is: " + cityName; editLocation.setText(s); } @Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {} }

Siempre puedes usar LocationManager.getLastKnownLocation () pero como dice que podría estar desactualizado.

Y una forma simple de obtener una ubicación general podría ser registrarse para la red (generalmente bastante rápido).

 LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1000, this); 

y luego haciendo

 locationManager.removeUpdates(this); 

en el método onLocationChanged() del oyente.

He escrito un tutorial detallado que cubre la ubicación actual aquí en demonuts.com . Puede encontrar más información aquí y también puede descargar el código fuente completo de la demostración para una mejor comprensión.

Ya hay muchas respuestas allí, pero quiero mostrar la última forma de obtener ubicación usando la API de Google, para que los nuevos progtwigdores puedan usar el nuevo método:

Antes que nada, pon esto en el archivo gradle

 compile 'com.google.android.gms:play-services:8.4.0' 

luego implementa las interfaces necesarias

 public class MainActivity extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener 

declarar instancias

  private GoogleApiClient mGoogleApiClient; private Location mLocation; private LocationManager locationManager; private LocationRequest mLocationRequest; 

pon esto en onCreate()

  mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

Por último, anule los métodos necesarios

  @Override public void onConnected(Bundle bundle) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); if(mLocation == null){ startLocationUpdates(); } if (mLocation != null) { double latitude = mLocation.getLatitude(); double longitude = mLocation.getLongitude(); } else { // Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show(); } } protected void startLocationUpdates() { // Create the location request mLocationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval(UPDATE_INTERVAL) .setFastestInterval(FASTEST_INTERVAL); // Request location updates if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); Log.d("reque", "--->>>>"); } @Override public void onConnectionSuspended(int i) { Log.i(TAG, "Connection Suspended"); mGoogleApiClient.connect(); } @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode()); } @Override public void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override public void onStop() { super.onStop(); if (mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } } @Override public void onLocationChanged(Location location) { } 

No te olvides de iniciar el GPS en tu dispositivo antes de ejecutar la aplicación.

No estoy seguro de si los Servicios Basados ​​en la Ubicación pueden obtener la ubicación de otras infraestructuras que no sean GPS, pero de acuerdo con ese artículo, parece posible:

Las aplicaciones pueden invocar cualquiera de varios tipos de métodos de posicionamiento.

Uso de la red del teléfono móvil: la identificación actual de la celda se puede usar para identificar la Base Transceptora Estacionaria (BTS) con la que el dispositivo se está comunicando y la ubicación de esa BTS. Claramente, la precisión de este método depende del tamaño de la celda y puede ser bastante inexacto. Una celda GSM puede tener entre 2 y 20 kilómetros de diámetro. Otras técnicas utilizadas junto con la identificación de la celda pueden lograr precisión dentro de los 150 metros.

Uso de satélites: el Sistema de Posicionamiento Global (GPS), controlado por el Departamento de Defensa de EE. UU., Utiliza una constelación de 24 satélites que orbitan alrededor de la Tierra. El GPS determina la posición del dispositivo al calcular las diferencias en el tiempo que las señales de diferentes satélites tardan en llegar al receptor. Las señales GPS están codificadas, por lo que el dispositivo móvil debe estar equipado con un receptor GPS. El GPS es potencialmente el método más preciso (entre 4 y 40 metros si el receptor GPS tiene una vista clara del cielo), pero tiene algunos inconvenientes: el hardware adicional puede ser costoso, consume batería mientras está en uso y requiere un poco de calor. después de un arranque en frío para obtener una solución inicial en los satélites visibles. También sufre de “efectos de cañón” en las ciudades, donde la visibilidad del satélite es intermitente.

Uso de balizas de posicionamiento de corto scope: en áreas relativamente pequeñas, como un solo edificio, una red de área local puede proporcionar ubicaciones junto con otros servicios. Por ejemplo, dispositivos apropiadamente equipados pueden usar Bluetooth para posicionamiento de corto scope.

Use el siguiente código, le dará el mejor proveedor disponible:

 String locCtx = Context.LOCATION_SERVICE; LocationManager locationMgr = (LocationManager) ctx.getSystemService(locCtx); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); String provider = locationMgr.getBestProvider(criteria, true); System.out.println("Best Available provider::::"+provider); 

La forma recomendada de hacerlo es usar LocationClient :

Primero, defina los valores del intervalo de actualización de ubicación. Ajuste esto a sus necesidades.

 private static final int MILLISECONDS_PER_SECOND = 1000; private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; private static final int FASTEST_INTERVAL_IN_SECONDS = 1; private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS; 

Haga que su Activity implemente GooglePlayServicesClient.ConnectionCallbacks , GooglePlayServicesClient.OnConnectionFailedListener y LocationListener .

 public class LocationActivity extends Activity implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {} 

Luego, configure un LocationClient en el método onCreate() de su Activity :

 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mLocationClient = new LocationClient(this, this, this); mLocationRequest = LocationRequest.create(); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setInterval(UPDATE_INTERVAL); mLocationRequest.setFastestInterval(FASTEST_INTERVAL); } 

Agregue los métodos requeridos a su Activity ; onConnected() es el método que se llama cuando se conecta el LocationClient . onLocationChanged() es donde recuperarás la ubicación más actualizada.

 @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.w(TAG, "Location client connection failed"); } @Override public void onConnected(Bundle dataBundle) { Log.d(TAG, "Location client connected"); mLocationClient.requestLocationUpdates(mLocationRequest, this); } @Override public void onDisconnected() { Log.d(TAG, "Location client disconnected"); } @Override public void onLocationChanged(Location location) { if (location != null) { Log.d(TAG, "Updated Location: " + Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude())); } else { Log.d(TAG, "Updated location NULL"); } } 

Asegúrese de conectar / desconectar el LocationClient para que solo use batería extra cuando sea absolutamente necesario y para que el GPS no se ejecute indefinidamente. El LocationClient debe estar conectado para obtener datos del mismo.

 public void onResume() { super.onResume(); mLocationClient.connect(); } public void onStop() { if (mLocationClient.isConnected()) { mLocationClient.removeLocationUpdates(this); } mLocationClient.disconnect(); super.onStop(); } 

Obtener la ubicación del usuario. Primero intente usar el LocationClient ; si eso falla, retroceda al LocationManager .

 public Location getLocation() { if (mLocationClient != null && mLocationClient.isConnected()) { return mLocationClient.getLastLocation(); } else { LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); if (locationManager != null) { Location lastKnownLocationGPS = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (lastKnownLocationGPS != null) { return lastKnownLocationGPS; } else { return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } } else { return null; } } } 

Actualy we can use the two providers both. And they just share a public listener:

 locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, (float) 10.0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 90 * 1000, (float) 10.0, listener); 

This is necessary because the OnLocationChanged() method always need to be called in time.

This is the code that provides user current location

create Maps Activty:

 public class Maps extends MapActivity { public static final String TAG = "MapActivity"; private MapView mapView; private LocationManager locationManager; Geocoder geocoder; Location location; LocationListener locationListener; CountDownTimer locationtimer; MapController mapController; MapOverlay mapOverlay = new MapOverlay(); @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); initComponents(); mapView.setBuiltInZoomControls(true); mapView.setSatellite(true); mapView.setTraffic(true); mapView.setStreetView(true); mapController = mapView.getController(); mapController.setZoom(16); locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); if (locationManager == null) { Toast.makeText(Maps.this, "Location Manager Not Available", Toast.LENGTH_SHORT).show(); return; } location = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location == null) location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { double lat = location.getLatitude(); double lng = location.getLongitude(); Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng, Toast.LENGTH_SHORT).show(); GeoPoint point = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6)); mapController.animateTo(point, new Message()); mapOverlay.setPointToDraw(point); List listOfOverlays = mapView.getOverlays(); listOfOverlays.clear(); listOfOverlays.add(mapOverlay); } locationListener = new LocationListener() { public void onStatusChanged(String arg0, int arg1, Bundle arg2) {} public void onProviderEnabled(String arg0) {} public void onProviderDisabled(String arg0) {} public void onLocationChanged(Location l) { location = l; locationManager.removeUpdates(this); if (l.getLatitude() == 0 || l.getLongitude() == 0) { } else { double lat = l.getLatitude(); double lng = l.getLongitude(); Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng, Toast.LENGTH_SHORT).show(); } } }; if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 10f, locationListener); locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 10f, locationListener); locationtimer = new CountDownTimer(30000, 5000) { @Override public void onTick(long millisUntilFinished) { if (location != null) locationtimer.cancel(); } @Override public void onFinish() { if (location == null) { } } }; locationtimer.start(); } public MapView getMapView() { return this.mapView; } private void initComponents() { mapView = (MapView) findViewById(R.id.map_container); ImageView ivhome = (ImageView) this.findViewById(R.id.imageView_home); ivhome.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { // TODO Auto-generated method stub Intent intent = new Intent(Maps.this, GridViewContainer.class); startActivity(intent); finish(); } }); } @Override protected boolean isRouteDisplayed() { return false; } class MapOverlay extends Overlay { private GeoPoint pointToDraw; public void setPointToDraw(GeoPoint point) { pointToDraw = point; } public GeoPoint getPointToDraw() { return pointToDraw; } @Override public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { super.draw(canvas, mapView, shadow); Point screenPts = new Point(); mapView.getProjection().toPixels(pointToDraw, screenPts); Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.select_map); canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 24, null); return true; } } } 

main.xml:

  < ?xml version="1.0" encoding="utf-8"?>    

and define following permission in manifest:

    

To get and show the user’s current location, you could also use MyLocationOverlay . Suppose you have a mapView field in your activity. All you would need to do to show the user location is the following:

 myLocationOverlay = new MyLocationOverlay(this, mapView); myLocationOverlay.enableMyLocation(); mapView.getOverlays().add(myLocationOverlay); 

This gets the current location from either the GPS or the network. If both fail, enableMyLocation() will return false .

As for the locations of things around the area, an ItemizedOverlay should do the trick.

I hope I haven’t misunderstood your question. Buena suerte.

EDIT: Updated with the latest Location Service API from Google Play Services library (July 2014)

I would recommend you to use the new Location Service API , available from the Google Play Services library, which provides a more powerful, high-level framework that automates tasks such as location provider choice and power management. According to the official documentation: “… Location API make it easy for you to build location-aware applications, without needing to focus on the details of the underlying location technology. They also let you minimize power consumption by using all of the capabilities of the device hardware.”

For further information visit: Making Your App Location-Aware

To see a full example using the latest Location Service API visit: Android LocationClient class is deprecated but used in documentation

Even though the answer is already given here. I just wanted to share this to the world incase the come across such scenario.

My requirement was that i needed to get a user’s current location within 30 to 35 seconds at max so here is the solution i made following Nirav Ranpara’s Answer .

1. I made MyLocationManager.java class which handles all the GPS and Network stuff

 import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import com.app.callbacks.OnLocationDetectectionListener; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.widget.Toast; public class MyLocationManager { /** The minimum distance to GPS change Updates in meters **/ private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS = 2; // 2 // meters /** The minimum time between GPS updates in milliseconds **/ private final long MIN_TIME_BW_UPDATES_OF_GPS = 1000 * 5 * 1; // 5 // seconds /** The minimum distance to NETWORK change Updates in meters **/ private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK = 5; // 5 // meters /** The minimum time between NETWORK updates in milliseconds **/ private final long MIN_TIME_BW_UPDATES_OF_NETWORK = 1000 * 10 * 1; // 10 // seconds /** * Lets just say i don't trust the first location that the is found. This is * to avoid that **/ private int NetworkLocationCount = 0, GPSLocationCount = 0; private boolean isGPSEnabled; private boolean isNetworkEnabled; /** * Don't do anything if location is being updated by Network or by GPS */ private boolean isLocationManagerBusy; private LocationManager locationManager; private Location currentLocation; private Context mContext; private OnLocationDetectectionListener mListener; public MyLocationManager(Context mContext, OnLocationDetectectionListener mListener) { this.mContext = mContext; this.mListener = mListener; } /** * Start the location manager to find my location */ public void startLocating() { try { locationManager = (LocationManager) mContext .getSystemService(Context.LOCATION_SERVICE); // Getting GPS status isGPSEnabled = locationManager .isProviderEnabled(LocationManager.GPS_PROVIDER); // Getting network status isNetworkEnabled = locationManager .isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isGPSEnabled && !isNetworkEnabled) { // No network provider is enabled showSettingsAlertDialog(); } else { // If GPS enabled, get latitude/longitude using GPS Services if (isGPSEnabled) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES_OF_GPS, MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS, gpsLocationListener); } if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES_OF_NETWORK, MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK, networkLocationListener); } } /** * My 30 seconds plan to get myself a location */ ScheduledExecutorService se = Executors .newSingleThreadScheduledExecutor(); se.schedule(new Runnable() { @Override public void run() { if (currentLocation == null) { if (isGPSEnabled) { currentLocation = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); } else if (isNetworkEnabled) { currentLocation = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } if (currentLocation != null && mListener != null) { locationManager.removeUpdates(gpsLocationListener); locationManager .removeUpdates(networkLocationListener); mListener.onLocationDetected(currentLocation); } } } }, 30, TimeUnit.SECONDS); } catch (Exception e) { Log.e("Error Fetching Location", e.getMessage()); Toast.makeText(mContext, "Error Fetching Location" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } /** * Handle GPS location listener callbacks */ private LocationListener gpsLocationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onLocationChanged(Location location) { if (GPSLocationCount != 0 && !isLocationManagerBusy) { Log.d("GPS Enabled", "GPS Enabled"); isLocationManagerBusy = true; currentLocation = location; locationManager.removeUpdates(gpsLocationListener); locationManager.removeUpdates(networkLocationListener); isLocationManagerBusy = false; if (currentLocation != null && mListener != null) { mListener.onLocationDetected(currentLocation); } } GPSLocationCount++; } }; /** * Handle Network location listener callbacks */ private LocationListener networkLocationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onLocationChanged(Location location) { if (NetworkLocationCount != 0 && !isLocationManagerBusy) { Log.d("Network", "Network"); isLocationManagerBusy = true; currentLocation = location; locationManager.removeUpdates(gpsLocationListener); locationManager.removeUpdates(networkLocationListener); isLocationManagerBusy = false; if (currentLocation != null && mListener != null) { mListener.onLocationDetected(currentLocation); } } NetworkLocationCount++; } }; /** * Function to show settings alert dialog. On pressing the Settings button * it will launch Settings Options. * */ public void showSettingsAlertDialog() { AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext); // Setting Dialog Title alertDialog.setTitle("GPS is settings"); // Setting Dialog Message alertDialog .setMessage("GPS is not enabled. Do you want to go to settings menu?"); // On pressing the Settings button. alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS); mContext.startActivity(intent); } }); // On pressing the cancel button alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); // Showing Alert Message alertDialog.show(); } } 

2. I made an Interface (callback) OnLocationDetectectionListener.java in order to communicate the results back to the calling fragment or activity

 import android.location.Location; public interface OnLocationDetectectionListener { public void onLocationDetected(Location mLocation); } 

3. Then i made an MainAppActivty.java Activity that implements OnLocationDetectectionListener interface and here is how i receive my location in it

 public class MainAppActivty extends Activity implements OnLocationDetectectionListener { private Location currentLocation; private MyLocationManager mLocationManager; @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_home); super.onCreate(savedInstanceState); mLocationManager = new MyLocationManager(this, this); mLocationManager.startLocating(); } @Override public void onLocationDetected(Location mLocation) { //Your new Location is received here currentLocation = mLocation; } 

4. Add the following permissions to your manifest file

   

Hope this is helpful to others 🙂

 public static Location getBestLocation(Context ctxt) { Location gpslocation = getLocationByProvider( LocationManager.GPS_PROVIDER, ctxt); Location networkLocation = getLocationByProvider( LocationManager.NETWORK_PROVIDER, ctxt); Location fetchedlocation = null; // if we have only one location available, the choice is easy if (gpslocation != null) { Log.i("New Location Receiver", "GPS Location available."); fetchedlocation = gpslocation; } else { Log.i("New Location Receiver", "No GPS Location available. Fetching Network location lat=" + networkLocation.getLatitude() + " lon =" + networkLocation.getLongitude()); fetchedlocation = networkLocation; } return fetchedlocation; } /** * get the last known location from a specific provider (network/gps) */ private static Location getLocationByProvider(String provider, Context ctxt) { Location location = null; // if (!isProviderSupported(provider)) { // return null; // } LocationManager locationManager = (LocationManager) ctxt .getSystemService(Context.LOCATION_SERVICE); try { if (locationManager.isProviderEnabled(provider)) { location = locationManager.getLastKnownLocation(provider); } } catch (IllegalArgumentException e) { Log.i("New Location Receiver", "Cannot access Provider " + provider); } return location; } 

Simple and best way for GeoLocation.

 LocationManager lm = null; boolean network_enabled; if (lm == null) lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE); network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); dialog = ProgressDialog.show(Kikit.this, "", "Fetching location...", true); final Handler handler = new Handler(); timer = new Timer(); TimerTask doAsynchronousTask = new TimerTask() { @Override public void run() { handler.post(new Runnable() { @Override public void run() { Log.e("counter value","value "+counter); if(counter< =8) { try { counter++; if (network_enabled) { lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE); Log.e("in network_enabled..","in network_enabled"); // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { if(attempt == false) { attempt = true; Log.e("in location listener..","in location listener.."); longi = location.getLongitude(); lati = location.getLatitude(); Data.longi = "" + longi; Data.lati = "" + lati; Log.e("longitude : ",""+longi); Log.e("latitude : ",""+lati); if(faceboo_name.equals("")) { if(dialog!=null){ dialog.cancel();} timer.cancel(); timer.purge(); Data.homepage_resume = true; lm = null; Intent intent = new Intent(); intent.setClass(Kikit.this,MainActivity.class); startActivity(intent); finish(); } else { isInternetPresent = cd.isConnectingToInternet(); if (isInternetPresent) { if(dialog!=null) dialog.cancel(); Showdata(); } else { error_view.setText(Data.internet_error_msg); error_view.setVisibility(0); error_gone(); } } } } public void onStatusChanged(String provider, int status, Bundle extras) { } public void onProviderEnabled(String provider) { //Toast.makeText(getApplicationContext(), "Location enabled", Toast.LENGTH_LONG).show(); } public void onProviderDisabled(String provider) { } }; // Register the listener with the Location Manager to receive // location updates lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 100000, 10,locationListener); } else{ //Toast.makeText(getApplicationContext(), "No Internet Connection.", 2000).show(); buildAlertMessageNoGps(); } } catch (Exception e) { // TODO // Auto-generated // catch // block } } else { timer.purge(); timer.cancel(); if(attempt == false) { attempt = true; String locationProvider = LocationManager.NETWORK_PROVIDER; // Or use LocationManager.GPS_PROVIDER try { Location lastKnownLocation = lm.getLastKnownLocation(locationProvider); longi = lastKnownLocation.getLongitude(); lati = lastKnownLocation.getLatitude(); Data.longi = "" + longi; Data.lati = "" + lati; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Log.i("exception in loc fetch", e.toString()); } Log.e("longitude of last known location : ",""+longi); Log.e("latitude of last known location : ",""+lati); if(Data.fb_access_token == "") { if(dialog!=null){ dialog.cancel();} timer.cancel(); timer.purge(); Data.homepage_resume = true; Intent intent = new Intent(); intent.setClass(Kikit.this,MainActivity.class); startActivity(intent); finish(); } else { isInternetPresent = cd.isConnectingToInternet(); if (isInternetPresent) { if(dialog!=null){ dialog.cancel();} Showdata(); } else { error_view.setText(Data.internet_error_msg); error_view.setVisibility(0); error_gone(); } } } } } }); } }; timer.schedule(doAsynchronousTask, 0, 2000); private void buildAlertMessageNoGps() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Your WiFi & mobile network location is disabled , do you want to enable it?") .setCancelable(false) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) { startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); setting_page = true; } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) { dialog.cancel(); finish(); } }); final AlertDialog alert = builder.create(); alert.show(); } 

A bit late here but what I would in such a situation is to use Google Maps API and mark the nearby locations using lat and long API of google maps. Plus user experience is better if you can show his/her location on a map. No need to bother about the updation of user location or frisking with android api. Let google maps handle the internals for you.

@emmby may have got it resolved in his app but for future reference a look at Google maps API for location specific stuff is what I recommend to fellow developers.

Edit: Link for displaying user location in google maps

It requires lots of things in place to get location updates in android, requires lots of bolierplate code.

You need to take care of

  • Google Play services availablity Check,
  • Update Google play Service if it is old or not available
  • Dialog Creation of GoogleApiClient and its callbacks connected,disconnected etc.
  • Stopping and releasing resources for location updates
  • Handling Location permission scenarios
  • Checking Location services are On or Off
  • Getting lastknown location is not so easy either
  • Fallback to last known location if not getting location after certain duration

I have created Android-EasyLocation (small android library) which will take care all this stuff and you can focus on business logic.

All you need is extend EasyLocationActivity and this

 requestSingleLocationFix(easyLocationRequest); 

o

 requestLocationUpdates(easyLocationRequest); 

Checkout sample app and steps needed here at https://github.com/akhgupta/Android-EasyLocation

This is the way I am requesting User Permissions.

Outside your application tag in AndroidManifest.xml add these permission requests.

    

Then add Google’s Location dependencies in the App Gradle file.

 implementation 'com.google.android.gms:play-services-location:15.0.0' 

Now declare some Global variables.

 private lateinit var mFusedLocationProvider:FusedLocationProviderClient private lateinit var mLocationCallback: LocationCallback private lateinit var mLocationRequest: LocationRequest private var mLocationPermissionGranted:Boolean = false 

In OnCreate method of your Activity (I was not able to Format the Code Properly, Apology for that)

 mFusedLocationProvider = LocationServices.getFusedLocationProviderClient(this) //Location Callback mLocationCallback = object: LocationCallback(){ override fun onLocationResult(p0: LocationResult?) { if(p0==null){ //todo(request user to enable location from settings then remove return) return }else{ getDeviceLocation() } } } //Location Request mLocationRequest = LocationRequest.create() mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY //Set the Interval for Latest Interval Update mLocationRequest.interval = 5000 //Set How Many Location Updated you Want mLocationRequest.numUpdates = 1 getLocationPermission() getDeviceLocation() 

Now create both the functions.

  private fun getLocationPermission() { val permission:Array = arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION,android.Manifest.permission.ACCESS_COARSE_LOCATION) if(ContextCompat.checkSelfPermission(applicationContext,Constant.FINE_LOCATION)== PermissionChecker.PERMISSION_GRANTED){ if(ContextCompat.checkSelfPermission(applicationContext,Constant.COARSE_LOCATION)== PermissionChecker.PERMISSION_GRANTED){ mLocationPermissionGranted = true } }else{ ActivityCompat.requestPermissions(this,permission,Constant.LOCATION_REQUEST_CODE) } } 

Second Method

 private fun getDeviceLocation() { try{ if(mLocationPermissionGranted){ mFusedLocationProvider.lastLocation.addOnCompleteListener(this,{task: Task -> if(task.isSuccessful){ var currentLocation: Location? = task.result if(currentLocation!=null){ Log.i("Location","Latitude is ${currentLocation.latitude} and Longitude" + "${currentLocation.longitude}") } else mFusedLocationProvider.requestLocationUpdates(mLocationRequest,mLocationCallback,null) } }) } }catch (e:SecurityException){ Log.e("Error", "Security Exception ${e.message}") } } 

For Constant.kt

 class Constant{ companion object { //Location Request Settings const val SET_INTERVAL:Long = 2000 const val NUM_UPDATES:Int = 1 //Location Permission const val FINE_LOCATION:String = android.Manifest.permission.ACCESS_FINE_LOCATION const val COARSE_LOCATION:String = android.Manifest.permission.ACCESS_COARSE_LOCATION } } 

By using FusedLocationProviderApi which is the latest API and the best among the available possibilities to get location in Android. add this in build.gradle file

 dependencies { compile 'com.google.android.gms:play-services:6.5.87' } 

you can get full source code by this url http://javapapers.com/android/android-location-fused-provider/

Here’s what I do:

  1. First of all I check whether NETWORK or GPS providers are enabled. Some may be disabled on the device, some may be disabled in application manifest. If any provider is enabled, I fetch cached last location for this provider and start location update listeners for this provider.
  2. There is a method to determine whether a location is better than last received location as mentioned in link :- https://developer.android.com/guide/topics/location/strategies.html#BestEstimate
  3. If I get update from location listener I check whether this location is better than previously received location. and If it is better than replace this location to previous best location( mFinalLocation ).
  4. There is also a handler(timer) for two minutes, which eventually stops the service and in onDestroy() method of service, stop listening for location updates for each of the provider.

Below is the code for service. You can run it based upon frequency of location update you need.

 import android.app.Service; import android.content.Context; import android.content.Intent; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.support.annotation.Nullable; import android.util.Log; public class RecordLocationService extends Service { private final String TAG = RecordLocationService.class.getSimpleName(); private final int TWO_MINUTES = 1000 * 60 * 2; private LocationManager mLocationManager; private MyLocationListener mLocationListeners[] = new MyLocationListener[]{ new MyLocationListener(LocationManager.NETWORK_PROVIDER), new MyLocationListener(LocationManager.GPS_PROVIDER) }; private Location mFinalLocation; private class MyLocationListener implements LocationListener { private String mProvider; public MyLocationListener(String provider) { Log.d(TAG, "LocationListener : " + provider); mProvider = provider; } public String getProvider() { return mProvider; } @Override public void onLocationChanged(Location location) { Log.d(TAG, "onLocationChanged : " + location); if (isBetterLocation(location, mFinalLocation)) { Log.d(TAG, "Setting current Final Location to recent most Location for Provider : " + location.getProvider()); Log.d(TAG, "Setting current Final Location to : " + location); mFinalLocation = location; } else { Log.d(TAG, "Keeping current Final Location to previous Final Location"); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(TAG, "onStatusChanged provider " + provider); } @Override public void onProviderEnabled(String provider) { Log.d(TAG, "onProviderEnabled provider " + provider); } @Override public void onProviderDisabled(String provider) { Log.d(TAG, "onProviderDisabled provider " + provider); } } private Handler mStopServiceHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: { stopSelf(); } break; } } }; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); Log.d(TAG, "onStartCommand"); return START_STICKY; } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate"); requestLocation(); mStopServiceHandler.sendEmptyMessageDelayed(1, TWO_MINUTES); } private void requestLocation() { // Acquire a reference to the system Location Manager if (mLocationManager == null) { mLocationManager = (LocationManager) this.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); } try { if (mLocationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER); Location cachedNetworkLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (cachedNetworkLocation != null) { Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER); Log.d(TAG, "Setting Final Location to : " + cachedNetworkLocation); mFinalLocation = cachedNetworkLocation; } else { Log.d(TAG, "Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER + " is NULL"); } Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.NETWORK_PROVIDER); mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocationListeners[0]); } } catch (SecurityException se) { Log.e(TAG, se.getMessage(), se); } catch (IllegalArgumentException iae) { Log.e(TAG, iae.getMessage(), iae); } try { if (mLocationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.GPS_PROVIDER); Location cachedGPSLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (cachedGPSLocation != null) { if (isBetterLocation(cachedGPSLocation, mFinalLocation)) { Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.GPS_PROVIDER); Log.d(TAG, "Setting Final Location to : " + cachedGPSLocation); mFinalLocation = cachedGPSLocation; } } else { Log.d(TAG, "Cached Location for Provider : " + LocationManager.GPS_PROVIDER + " is NULL"); } Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.GPS_PROVIDER); mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListeners[1]); } } catch (SecurityException se) { Log.e(TAG, se.getMessage(), se); } catch (IllegalArgumentException iae) { Log.e(TAG, iae.getMessage(), iae); } } /** * 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 boolean isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return true; } // Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; 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 true; // If the new location is more than two minutes older, it must be worse } else if (isSignificantlyOlder) { return false; } // 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 true; } else if (isNewer && !isLessAccurate) { return true; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return true; } return false; } /** * Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); if (mLocationManager != null) { for (int i = 0; i < mLocationListeners.length; i++) { try { Log.d(TAG, "Removing Location Update for Provider : " + mLocationListeners[i].getProvider()); mLocationManager.removeUpdates(mLocationListeners[i]); } catch (Exception ex) { Log.e(TAG, "fail to remove location listeners, ignore", ex); } } } } } 

Recently refactored to obtain the location of the code, learn some good ideas, and finally achieved a relatively perfect library and Demo.

 //request all valid provider(network/gps) private boolean requestAllProviderUpdates() { checkRuntimeEnvironment(); checkPermission(); if (isRequesting) { EasyLog.d("Request location update is busy"); return false; } long minTime = getCheckTimeInterval(); float minDistance = getCheckMinDistance(); if (mMapLocationListeners == null) { mMapLocationListeners = new HashMap<>(); } mValidProviders = getValidProviders(); if (mValidProviders == null || mValidProviders.isEmpty()) { throw new IllegalArgumentException("Not available provider."); } for (String provider : mValidProviders) { LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { if (location == null) { EasyLog.e("LocationListener callback location is null."); return; } printf(location); mLastProviderTimestamp = location.getTime(); if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { finishResult(location); } else { doLocationResult(location); } removeProvider(location.getProvider()); if (isEmptyValidProviders()) { requestTimeoutMsgInit(); removeUpdates(); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener); mMapLocationListeners.put(provider, locationListener); EasyLog.d("Location request %s provider update.", provider); } isRequesting = true; return true; } //remove request update public void removeUpdates() { checkRuntimeEnvironment(); LocationManager locationManager = getLocationManager(); if (mMapLocationListeners != null) { Set keys = mMapLocationListeners.keySet(); for (String key : keys) { LocationListener locationListener = mMapLocationListeners.get(key); if (locationListener != null) { locationManager.removeUpdates(locationListener); EasyLog.d("Remove location update, provider is " + key); } } mMapLocationListeners.clear(); isRequesting = false; } } //Compared with the last successful position, to determine whether you need to filter private boolean isNeedFilter(Location location) { checkLocation(location); if (mLastLocation != null) { float distance = location.distanceTo(mLastLocation); if (distance < getCheckMinDistance()) { return true; } if (location.getAccuracy() >= mLastLocation.getAccuracy() && distance < location.getAccuracy()) { return true; } if (location.getTime() <= mLastProviderTimestamp) { return true; } } return false; } private void doLocationResult(Location location) { checkLocation(location); if (isNeedFilter(location)) { EasyLog.d("location need to filtered out, timestamp is " + location.getTime()); finishResult(mLastLocation); } else { finishResult(location); } } //Return to the finished position private void finishResult(Location location) { checkLocation(location); double latitude = location.getLatitude(); double longitude = location.getLongitude(); float accuracy = location.getAccuracy(); long time = location.getTime(); String provider = location.getProvider(); if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty()) { String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s"; EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider)); mLastLocation = location; synchronized (this) { Iterator iterator = mLocationResultListeners.iterator(); while (iterator.hasNext()) { LocationResultListener listener = iterator.next(); if (listener != null) { listener.onResult(location); } iterator.remove(); } } } } 

Complete code: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

*Each request to complete the location, it is best to removeUpdates, otherwise the phone status bar will always display the positioning icon.

After seeing all the answers, and question ( Simplest and Robust ). I got clicked about only library Android-ReactiveLocation .

When i made an location tracking app. Then i realized that its very typical to handle location tracking with optimised with battery.

So i want tell freshers and also developers who don’t want to maintain their location code with future optimisations. Use this library.

 ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(context); locationProvider.getLastKnownLocation() .subscribe(new Consumer() { @Override public void call(Location location) { doSthImportantWithObtainedLocation(location); } }); 

Dependencies to put in app level build.gradle

 dependencies { ... compile 'pl.charmas.android:android-reactive-location2:2.1@aar' compile 'com.google.android.gms:play-services-location:11.0.4' //you can use newer GMS version if you need compile 'com.google.android.gms:play-services-places:11.0.4' compile 'io.reactivex:rxjava:2.0.5' //you can override RxJava version if you need } 

Pros to use this lib:

  • This lib is and will be actively maintained.
  • You dont worry about battery optimisation. As developers have done their best.
  • Easy installation, put dependency and play.
  • easily connect to Play Services API
  • obtain last known location
  • subscribe for location updates use
  • location settings API
  • manage geofences
  • geocode location to list of addresses
  • activity recognition
  • use current place API fetch place
  • autocomplete suggestions

From last more than one year, I was using the combination of GPS_PROVIDER and NETWORK_PROVIDER to get the current location and it was working good, but from last few months I’m getting location after a long delay, so I switched to latest API FusedLocationProviderClient and it is working pretty good.

Here is the class which I wrote to get current location by using FusedLocationProviderClient. In below code, I used a timer to wait for while to get the current location, I scheduled timer 15 seconds delay, you can change it according to you.

 private static FusedLocationService ourInstance; private final LocationRequest locationRequest; private FusedLocationProviderClient mFusedLocationClient; private Location mLastLocation; private Context context; private FindOutLocation findOutLocation; private boolean callbackTriggered = false; private Timer timer; public static FusedLocationService getInstance(Context pContext) { if (null == ourInstance) ourInstance = new FusedLocationService(pContext); return ourInstance; } private FusedLocationService(Context pContext) { context = pContext; mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context); locationRequest = getLocationRequest(); requestLocation(context); } public Location getLastKnownLocation() { return mLastLocation; } private void requestLocation(Context context) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } mFusedLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, null); mFusedLocationClient.getLastLocation().addOnSuccessListener(location -> { if (location != null) { mLastLocation = location; triggerCallback(mLastLocation); } }); } private LocationRequest getLocationRequest() { LocationRequest locationRequest = new LocationRequest(); long INTERVAL = 10 * 1000; long FASTEST_INTERVAL = 5 * 1000; locationRequest.setInterval(INTERVAL); locationRequest.setFastestInterval(FASTEST_INTERVAL); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); return locationRequest; } private LocationCallback mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { for (Location location : locationResult.getLocations()) { if (location != null) mLastLocation = location; } if (null != mLastLocation) triggerCallback(mLastLocation); } }; public static abstract class FindOutLocation { public abstract void gotLocation(Location location); } @SuppressLint("MissingPermission") public void findLocation(FindOutLocation findOutLocation) { long TIMER_TIME_OUT = 15 * 1000; this.findOutLocation = findOutLocation; callbackTriggered = false; try { requestLocation(context); timer = new Timer(); timer.schedule(new GetLastLocation(context), TIMER_TIME_OUT); } catch (Exception e) { e.printStackTrace(); } } private class GetLastLocation extends TimerTask { Context context; GetLastLocation(Context context) { this.context = context; } @Override public void run() { triggerCallback(mLastLocation); } } private void triggerCallback(Location location) { if (null != location) mLastLocation = location; if (!callbackTriggered && null != findOutLocation) { callbackTriggered = true; removeLocationUpdates(); findOutLocation.gotLocation(location); findOutLocation = null; } } private void removeLocationUpdates() { if (null != timer) timer.cancel(); if (null != mFusedLocationClient) mFusedLocationClient.removeLocationUpdates(mLocationCallback); } } 

And called this from activity, here is the code

  FusedLocationService.FindOutLocation findOutLocation = new FusedLocationService.FindOutLocation() { @Override public void gotLocation(Location currentLocation) { if (currentLocation != null) { /*TODO DO SOMETHING WITH CURRENT LOCATION*/ } } }; FusedLocationService.getInstance(this).findLocation(findOutLocation); 

Add following entries in the AndroidManifest.xml

     

Before I answer, I just want to be upfront about the fact that I’m affiliated with Neura. Now to your question. So, instead of wasting your time behind coding to get your user’s location, you can use our SDK. It takes less than 30 mins to integrate. Neura provides you with your user’s location/activity,and you can configure your application accordingly to perform certain tasks after you receive the data. Here’s a few reasons to use Neura over other Activity recognition API’s:

  1. No need to code tons of lines to understand your user.
  2. Gives you accurate results.
  3. Consumes less than 1% of your battery.