ubicacion tiempo studio real puede posicionamiento obtener localizacion con actual android geolocation location latitude-longitude

tiempo - ¿Cuál es la forma más sencilla y robusta de obtener la ubicación actual del usuario en Android?



obtener ubicacion gps android studio (25)

Con la solución de Fedor, he experimentado la ejecución múltiple de callback gotLocation . Parece que se debe a una condición de carrera en el método LocationListener.onLocationChanged anulado, cuando el método gotLocation es ''lo suficientemente largo'' . No estoy seguro, pero supongo que removeUpdates evita la puesta en cola de nuevos mensajes en la cola de Looper, pero no elimina los que ya están en cola pero 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 aún 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, que usa 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); } }

Utilizo esta clase de un hilo de bucle 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.

El LocationManager API 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 en sí misma, pero sí necesita obtener la ubicación del usuario para mostrar una lista de empresas cercanas. No tiene que preocuparse si el usuario se está moviendo o algo así.

Esto es lo que me gustaría hacer:

  1. Mostrar al usuario una lista de lugares cercanos.
  2. Precargue la ubicación del usuario para que, para cuando lo necesite en la Activity X, esté disponible.
  3. No me importa especialmente la precisión o la frecuencia de actualización. Basta con agarrar una ubicación es suficiente siempre y cuando no esté muy lejos. Tal vez, si quiero ser elegante, actualizaré la ubicación una vez cada unos minutos, pero no es una gran prioridad.
  4. Trabaje 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 elegir dos proveedores de ubicación diferentes (GPS y RED) y administrar el ciclo de vida de cada uno. No solo eso, sino que tengo que duplicar el mismo código en varias actividades para satisfacer el # 2. He intentado usar getBestProvider() en el pasado para reducir la solución a solo usar un proveedor de ubicación, pero parece que solo te da el mejor proveedor "teórico" en lugar del proveedor que realmente te dará los mejores resultados.

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


Después de buscar la mejor implementación, cómo obtener la mejor ubicación 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); Iterable<GpsSatellite>satellites = status.getSatellites(); sat_count = 0; Iterator<GpsSatellite>satI = 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. De lo contrario, devuelve LocationManager.getBestProvider() ubicación. Revisa el código!


Esto es lo que hago:

  1. En primer lugar, compruebo qué proveedores están habilitados. Algunos pueden estar deshabilitados en el dispositivo, otros pueden estar deshabilitados en el manifiesto de la aplicación.
  2. Si hay algún proveedor disponible, comienzo a los oyentes de ubicación y al temporizador de tiempo de espera. Es 20 segundos en mi ejemplo, puede que no sea suficiente para el GPS, por lo que puede ampliarlo.
  3. Si obtengo una actualización del escucha de ubicación, uso el valor proporcionado. Dejo de oyentes y temporizador.
  4. Si no recibo ninguna actualización y transcurre el tiempo, tengo que usar los últimos valores conocidos.
  5. Tomo los últimos valores conocidos de los proveedores disponibles y elijo el más reciente de ellos.

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 de 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 obtiene una actualización del proveedor de la red, no detenga los escuchas sino que continúe esperando. El GPS da datos más precisos por lo que vale la pena esperar. Si el temporizador transcurre y tiene actualización desde la red pero no desde el 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 que Google Play Services apk esté instalado en el dispositivo del usuario.


Esto es lo que hago:

  1. En primer lugar, compruebo si los proveedores de RED o GPS están habilitados. Algunos pueden estar deshabilitados en el dispositivo, otros pueden estar deshabilitados en el manifiesto de la aplicación. Si algún proveedor está habilitado, busco la última ubicación en caché para este proveedor e inicio los escuchas de actualización de ubicación para este proveedor.
  2. Existe un método para determinar si una ubicación es mejor que la última ubicación recibida como se menciona en el enlace: - https://developer.android.com/guide/topics/location/strategies.html#BestEstimate
  3. Si recibo una actualización del detector de ubicación, compruebo si esta ubicación es mejor que la ubicación recibida anteriormente. y si es mejor que reemplazar esta ubicación por la mejor ubicación anterior ( mFinalLocation).
  4. También hay un controlador (temporizador) durante dos minutos, que eventualmente detiene el servicio y, en el onDestroy()método de servicio, deja de escuchar las actualizaciones de ubicación para cada uno de los proveedores.

A continuación se muestra el código de servicio. Puede ejecutarlo según la frecuencia de actualización de ubicación que necesite.

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); } } } } }


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

Código fuente de ejemplo completo en la siguiente URL:

Obtenga las coordenadas de la ubicación actual, nombre de la ciudad - en Android

Vea cómo funciona:

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

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"> </uses-permission>

  • y crear una instancia de LocationManager como esta

    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

  • Comprobar si el 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 ejemplo 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<Address> 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) {} }


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

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

En primer lugar, poner esto en el archivo de gradle

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

luego implementar 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 fin, anular 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 olvides iniciar el GPS en tu dispositivo antes de ejecutar la aplicación.


La forma recomendada de hacer esto es usar LocationClient :

Primero, defina los valores del intervalo de actualización de la ubicación. Ajusta esto a tus 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 LocationClientconecta. 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 LocationClientpara que solo use una batería adicional cuando sea absolutamente necesario y para que el GPS no funcione indefinidamente. El LocationClientdebe estar conectado para obtener datos de él.

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 intenta usar el LocationClient; Si eso falla, vuelve a la 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; } } }


No estoy seguro de si los Servicios basados ​​en la ubicación pueden obtener la ubicación de otras infraestructuras distintas del GPS, pero de acuerdo con ese artículo, parece posible:

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

Uso de la red de telefonía móvil: la ID de celda actual se puede usar para identificar la Estación Transceptora Base (BTS) con la que se está comunicando el dispositivo 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 inexacta. Una celda GSM puede tener de 2 a 20 kilómetros de diámetro. Otras técnicas utilizadas junto con la identificación de celda pueden lograr una precisión dentro de los 150 metros.

Uso de satélites: El Sistema de posicionamiento global (GPS), controlado por el Departamento de Defensa de los Estados Unidos, utiliza una constelación de 24 satélites que orbitan la Tierra. El GPS determina la posición del dispositivo calculando las diferencias en el tiempo que tardan las señales de los diferentes satélites 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 algo de calor. arriba 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 alcance: en áreas relativamente pequeñas, como en un solo edificio, una red de área local puede proporcionar ubicaciones junto con otros servicios. Por ejemplo, los dispositivos equipados adecuadamente pueden usar Bluetooth para posicionamiento de corto alcance.


Siempre se puede 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 en 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.


Utilice 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);


EDITAR: actualizado con la última versión del servicio de ubicación de la biblioteca de Google Play Services (julio de 2014)

Le recomendaría utilizar la nueva API del Servicio de ubicación , disponible en la biblioteca de Google Play Services, que proporciona un marco de alto nivel más potente que automatiza tareas como la elección del proveedor de ubicación y la administración de energía. De acuerdo con la documentación oficial: "... La API de ubicación le facilita la creación de aplicaciones conscientes de la ubicación, sin tener que centrarse en los detalles de la tecnología de ubicación subyacente. También le permiten minimizar el consumo de energía al usar todas las capacidades del hardware del dispositivo ".

Para más información, visite: Cómo hacer que su aplicación sea consciente de su ubicación.

Para ver un ejemplo completo utilizando la última visita del API del servicio de ubicación: la clase de LocationClient de Android está en desuso pero se usa en la documentación


Simple y la mejor manera de 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(); }


Desde hace más de un año, estuve usando la combinación de GPS_PROVIDER y NETWORK_PROVIDER para obtener la ubicación actual y funcionó bien, pero desde los últimos meses obtuve una ubicación después de un largo retraso, así que cambié a la última API FusedLocationProviderClient y esta funcionando bastante bien

Aquí está la clase que escribí para obtener la ubicación actual usando FusedLocationProviderClient. En el siguiente código, utilicé un temporizador para esperar el tiempo para obtener la ubicación actual, programé el temporizador con 15 segundos de retraso, puede cambiarlo según lo desee.

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); } }

Y esto se llama de la actividad, aquí está el código

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);

Agregue las siguientes entradas en el AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />


Esta es la forma en que estoy solicitando permisos de usuario.

Fuera de su etiqueta de aplicación en AndroidManifest.xml agregue estas solicitudes de permiso.

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

A continuación, agregue las dependencias de ubicación de Google en el archivo Gradle de aplicaciones.

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

Ahora declare algunas variables globales.

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

En el método OnCreate de su actividad (no pude formatear el código correctamente, disculpas por eso)

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()

Ahora crea ambas funciones.

private fun getLocationPermission() { val permission:Array<String> = 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) } }

Segundo método

private fun getDeviceLocation() { try{ if(mLocationPermissionGranted){ mFusedLocationProvider.lastLocation.addOnCompleteListener(this,{task: Task<Location> -> 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}") } }

Para 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 } }


Este es el código que proporciona la ubicación actual del usuario.

crear 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<Overlay> 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"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" android:orientation="vertical" > <com.google.android.maps.MapView android:id="@+id/map_container" android:layout_width="fill_parent" android:layout_height="fill_parent" android:apiKey="yor api key" android:clickable="true" android:focusable="true" /> </LinearLayout>

y define el siguiente permiso en manifiesto:

<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


Recientemente refactorizado para obtener la ubicación del código, aprender algunas buenas ideas y finalmente obtener una biblioteca y una demostración relativamente perfectas.

//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<String> 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<LocationResultListener> iterator = mLocationResultListeners.iterator(); while (iterator.hasNext()) { LocationResultListener listener = iterator.next(); if (listener != null) { listener.onResult(location); } iterator.remove(); } } } }

Código completo: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java

* Cada solicitud para completar la ubicación, es mejor eliminar Actualizaciones, de lo contrario, la barra de estado del teléfono siempre mostrará el ícono de posicionamiento.


Requiere muchas cosas para obtener actualizaciones de ubicación en Android, requiere un montón de código de bolier.

Necesitas cuidar de

  • Disponibilidad de los servicios de Google Play.
  • Actualiza Google Play Service si es antiguo o no está disponible.
  • Creación de diálogos de GoogleApiClient y sus devoluciones de llamadas conectadas, desconectadas, etc.
  • Detener y liberar recursos para actualizaciones de ubicación
  • Manejo de escenarios de permisos de ubicación
  • Comprobación de los servicios de ubicación están activados o desactivados
  • Conseguir la última ubicación tampoco es tan fácil
  • Retroceder a la última ubicación conocida si no se obtiene la ubicación después de cierta duración

He creado Android-EasyLocation (pequeña biblioteca de Android) que se encargará de todo esto y podrás concentrarte en la lógica empresarial.

Todo lo que necesita es extender EasyLocationActivity y esto

requestSingleLocationFix(easyLocationRequest);

o

requestLocationUpdates(easyLocationRequest);

La aplicación de ejemplo de Checkout y los pasos son necesarios aquí en https://github.com/akhgupta/Android-EasyLocation


Actualmente podemos utilizar los dos proveedores tanto. Y solo comparten un oyente público:

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

Esto es necesario porque el método OnLocationChanged () siempre debe llamarse a tiempo.


Al utilizar FusedLocationProviderApi, que es la última API y la mejor entre las posibilidades disponibles para obtener la ubicación en Android. agrega esto en el archivo build.gradle

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

puede obtener el código fuente completo a través de esta url http://javapapers.com/android/android-location-fused-provider/


Antes de responder, solo quiero ser sincero sobre el hecho de que estoy afiliado a Neura. Ahora a tu pregunta. Por lo tanto, en lugar de perder su tiempo detrás de la codificación para obtener la ubicación de su usuario, puede usar nuestro SDK. Se tarda menos de 30 minutos en integrarse. Neura le proporciona la ubicación / actividad de su usuario, y puede configurar su aplicación en consecuencia para realizar ciertas tareas después de recibir los datos. Aquí hay algunas razones para usar Neura sobre otras API de reconocimiento de actividad:

  1. No es necesario codificar toneladas de líneas para comprender a su usuario.
  2. Te da resultados precisos.
  3. Consume menos del 1% de tu batería.

Aunque la respuesta ya está dada aquí. Solo quería compartir esto con el mundo en caso de que se presentara en ese escenario.

Mi requerimiento era que necesitaba obtener la ubicación actual de un usuario dentro de 30 a 35 segundos como máximo, así que aquí está la solución que encontré después de la Respuesta de Nirav Ranpara .

1. Hice MyLocationManager.java clase que se encarga de toda la red GPS y otras cosas

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. Hice una Interfaz (devolución de llamada) OnLocationDetectectionListener.java para comunicar los resultados al fragmento o actividad de llamada

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

3. Luego hice una actividad MainAppActivty.java que implementa la OnLocationDetectectionListenerinterfaz y aquí es cómo recibo mi ubicación en ella.

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. Agregue los siguientes permisos a su archivo de manifiesto

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Espero que esto sea de ayuda para otros :)


Después de ver todas las respuestas, y la pregunta (Más simple y robusta ). Me hice clic en solo la biblioteca Android-ReactiveLocation .

Cuando hice una aplicación de seguimiento de ubicación. Entonces me di cuenta de que es muy típico manejar el seguimiento de ubicación con batería optimizada.

Así que quiero informar a los expertos y también a los desarrolladores que no quieren mantener su código de ubicación con futuras optimizaciones. Usa esta biblioteca.

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

Dependencias para poner en el nivel de aplicación 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 para usar esta lib:

  • Esta lib es y será mantenida activamente.
  • No te preocupes por la optimización de la batería. Como los desarrolladores han hecho todo lo posible.
  • Fácil instalación, poner dependencia y jugar.
  • Conéctate fácilmente a Play Services API
  • obtener la última ubicación conocida
  • suscribirse para uso de actualizaciones de ubicación
  • configuración de ubicación API
  • gestionar geofences
  • ubicación de geocodificación a la lista de direcciones
  • reconocimiento de actividades
  • utilizar el lugar actual de búsqueda de lugar API
  • sugerencias de autocompletar

Para obtener y mostrar la ubicación actual del usuario, también puede utilizar MyLocationOverlay. Supongamos que tienes un mapViewcampo en tu actividad. Todo lo que necesita hacer para mostrar la ubicación del usuario es lo siguiente:

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

Esto obtiene la ubicación actual del GPS o de la red. Si ambos fallan, enableMyLocation()volveremos false.

En cuanto a la ubicación de las cosas alrededor del área, una ItemizedOverlaydebe hacer el truco.

Espero no haber malinterpretado tu pregunta. Buena suerte.


Un poco tarde aquí, pero lo que haría en tal situación es utilizar la API de Google Maps y marcar las ubicaciones cercanas utilizando la API de latitud y larga de Google Maps. Además, la experiencia del usuario es mejor si puede mostrar su ubicación en un mapa. No hay necesidad de preocuparse por la actualización de la ubicación del usuario o de jugar con la API de Android. Deje que Google Maps se encargue de los aspectos internos por usted.

Es posible que @emmby lo haya resuelto en su aplicación, pero para futuras referencias, un vistazo a la API de Google maps para obtener información específica de la ubicación es lo que recomiendo a otros desarrolladores.

Editar: Enlace para mostrar la ubicación del usuario en google maps


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; }