Android: LocationManager vs Google Play Services

Quiero crear una aplicación que se centre en obtener la ubicación actual del usuario y luego buscar puntos de interés (como bares, restaurantes, etc.) que estén cerca de él a través de la API de Google Places .

Al buscar en la web un lugar para comenzar encontré algunos tutoriales que usan la clase LocationManager y algunos otros que usan Google Play Services para encontrar la ubicación de los usuarios.

A primera vista, ambos hacen lo mismo, pero como soy nuevo en esto, me confundí un poco y no sé qué método se adapta mejor a mis necesidades. Entonces, quiero preguntarte:

¿Cuáles son las diferencias entre estos dos métodos para encontrar ubicaciones (si las hay)?

Ubicación del usuario en Android

Obtener la ubicación del usuario en Android es un poco menos directo que en iOS. Para comenzar la confusión, hay dos formas totalmente diferentes de hacerlo. El primero es usar las API de Android de android.location.LocationListener , y el segundo es usar las API de servicios de Google Play com.google.android.gms.location.LocationListener . Repasemos ambos.

  1. API de ubicación de Android

    Las API de ubicación de Android usan tres proveedores diferentes para obtener ubicación:

    • LocationManager.GPS_PROVIDER : este proveedor determina la ubicación usando satélites. Dependiendo de las condiciones, este proveedor puede tomar un tiempo para devolver una corrección de ubicación.
    • LocationManager.NETWORK_PROVIDER : este proveedor determina la ubicación según la disponibilidad de la torre de la celda y los puntos de acceso WiFi. Los resultados se recuperan mediante una búsqueda de red.
    • LocationManager.PASSIVE_PROVIDER : este proveedor devolverá las ubicaciones generadas por otros proveedores. Usted recibe pasivamente actualizaciones de ubicación cuando otras aplicaciones o servicios las solicitan sin solicitarlas usted mismo.

La esencia de esto es que obtienes un objeto de LocationManager del sistema, implementas el LocationListener y llamas a requestLocationUpdates en el LocationManager .

Aquí hay un fragmento de código:

  LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { // Called when a new location is found by the network location provider. makeUseOfNewLocation(location); } public void onStatusChanged(String provider, int status, Bundle extras) {} public void onProviderEnabled(String provider) {} public void onProviderDisabled(String provider) {} }; // Register the listener with the Location Manager to receive location updates locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); 

La guía API de Google sobre estrategias de ubicación explica el código bastante bien. Pero también mencionan que, en la mayoría de los casos, obtendrá un mejor rendimiento de la batería, así como una precisión más apropiada, al usar la API de servicios de ubicación de Google . ¡Ahora comienza la confusión!

  1. API de servicios de ubicación de Google

La API de servicios de ubicación de Google forma parte del APK de servicios de Google Play ( aquí se explica cómo configurarlo ). Están construidos sobre la API de Android. Estas API proporcionan un “proveedor de ubicación fusionada” en lugar de los proveedores mencionados anteriormente. Este proveedor elige automáticamente qué proveedor subyacente utilizar, en función de la precisión, el uso de la batería, etc. Es rápido porque obtiene la ubicación de un servicio de todo el sistema que la sigue actualizando. Y puede usar funciones más avanzadas como geofencing.

Para utilizar los Servicios de ubicación de Google, su aplicación debe conectarse al GooglePlayServicesClient . Para conectarse con el cliente, su actividad (o fragmento, más o menos) necesita implementar las interfaces GooglePlayServicesClient.ConnectionCallbacks y GooglePlayServicesClient.OnConnectionFailedListener . Aquí hay un código de muestra:

  public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener { LocationClient locationClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); locationClient = new LocationClient(this, this, this); } @Override public void onConnected(Bundle bundle) { Location location = locationClient.getLastLocation() ; Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show(); } @Override public void onDisconnected() { Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show(); } @Override public void onConnectionFailed(ConnectionResult connectionResult) { // code to handle failed connection // this code can be found here — http://developer.android.com/training/location/retrieve-current.html } 
  • ¿Por qué es locationClient.getLastLocation() nulo?

El locationClient.getLastLocation() obtiene la última ubicación conocida del cliente. Sin embargo, el proveedor de ubicación fusionada solo mantendrá la ubicación de fondo si al menos un cliente está conectado a ella. Una vez que el primer cliente se conecta, inmediatamente intentará obtener una ubicación. Si su actividad es el primer cliente que se conecta y llama a getLastLocation() inmediato en onConnected() , puede que no sea suficiente tiempo para que onConnected() la primera ubicación. Esto dará como resultado que la location sea null .

Para resolver este problema, debe esperar (indeterminadamente) hasta que el proveedor obtenga la ubicación y luego llamar a getLastLocation() , que es imposible de conocer. Otra (mejor) opción es implementar la interfaz com.google.android.gms.location.LocationListener para recibir actualizaciones de ubicación periódicas (y desactivarla una vez que obtenga la primera actualización).

  public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { // . . . . . . . . more stuff here LocationRequest locationRequest; LocationClient locationClient; @Override protected void onCreate(Bundle savedInstanceState) { // . . . . other initialization code locationClient = new LocationClient(this, this, this); locationRequest = new LocationRequest(); // Use high accuracy locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Set the update interval to 5 seconds locationRequest.setInterval(UPDATE_INTERVAL); // Set the fastest update interval to 1 second locationRequest.setFastestInterval(FASTEST_INTERVAL); } // . . . . . . . . other methods @Override public void onConnected(Bundle bundle) { Location location = locationClient.getLastLocation(); if (location == null) locationClient.requestLocationUpdates(locationRequest, this); else Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show(); } // . . . . . . . . other methods @Override public void onLocationChanged(Location location) { locationClient.removeLocationUpdates(this); // Use the location here!!! } 

En este código, está comprobando si el cliente ya tiene la última ubicación (en onConnected ). De lo contrario, está solicitando actualizaciones de ubicación y apagando las solicitudes (en callback onLocationChanged() ) tan pronto como reciba una actualización.

Tenga en cuenta que locationClient.requestLocationUpdates(locationRequest, this); tiene que estar dentro de la onConnected llamada onConnected , de lo contrario obtendrá una IllegalStateException porque intentará solicitar ubicaciones sin estar conectado al Cliente de servicios de Google Play.

  • El usuario ha deshabilitado los servicios de ubicación

Muchas veces, el usuario tendría deshabilitados los servicios de ubicación (para ahorrar batería o razones de privacidad). En tal caso, el código anterior aún solicitará actualizaciones de ubicación, pero nunca se onLocationChanged a onLocationChanged . Puede detener las solicitudes comprobando si el usuario ha deshabilitado los servicios de ubicación.

Si su aplicación requiere que activen los servicios de ubicación, querrá mostrar un mensaje o un brindis. Desafortunadamente, no hay forma de verificar si el usuario ha deshabilitado servicios de ubicación en la API de servicios de ubicación de Google. Para esto, tendrás que recurrir a la API de Android.

En tu método onCreate :

  LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { locationEnabled = false; Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show(); } else locationEnabled = true; 

Y usa el onConnected locationEnabled en tu método onConnected como este:

  if (location != null) { Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show(); } else if (location == null && locationEnabled) { locationClient.requestLocationUpdates(locationRequest, this); } 

gracias a Rahul Jiresal

Debe utilizar la API de ubicación de servicios de Google Play en lugar de LocationManager. De acuerdo con los documentos:

Las API de ubicación de servicios de Google Play son preferibles a las API de ubicación de Android Framework (android.location) como una forma de agregar conocimiento de ubicación a su aplicación. Si actualmente está utilizando las API de ubicación de Android Framework, le recomendamos encarecidamente que cambie a las API de ubicación de los servicios de Google Play lo antes posible.

En cuanto a por qué cambiar, Google dice esto:

La API de servicios de ubicación de Google, parte de los servicios de Google Play, proporciona un marco de alto nivel más poderoso que maneja automáticamente los proveedores de ubicación, el movimiento del usuario y la precisión de la ubicación. También maneja la progtwigción de actualización de ubicación en función de los parámetros de consumo de energía que proporcione. En la mayoría de los casos, obtendrá un mejor rendimiento de la batería, así como una precisión más apropiada, mediante la API de servicios de ubicación.

En mi experiencia, “precisión más apropiada” no significa mejor de ninguna manera. A menos que me falta algo, si desea asegurarse de que se utiliza el GPS, LocationManager es la única manera de hacerlo. Rastreamos vehículos con nuestra aplicación y, de nuevo, a menos que me falta algo, Google Play Services proporciona algunas ubicaciones muy inexactas con bastante frecuencia.

He estado usando la API de Google Location Services por bastante tiempo. Tiene ventajas, ya que encapsula la complejidad de tener varias fonts para determinar las posiciones. Sin embargo, se encapsula demasiado , por lo que cuando obtienes una posición extraña, no tienes forma de determinar de dónde proviene esa extraña posición.

En la vida real, he tenido varios valores anormales emergentes, a 10 de kilómetros de distancia de la posición real. La única explicación es que estas localizaciones locas se deben a errores en las bases de datos de Googles Wi-Fi o NWK, errores que siempre estarán presentes, ya que las topologías de Wi-Fi y de red cambian todos los días. Pero desafortunadamente (y sorprendentemente) la API no le da información sobre cómo se derivó una posición individual.

enter image description here

Esto te deja con el problema de tener que filtrar los valores anormales basados ​​en la verosimilitud de verificar la velocidad, la aceleración, el rumbo, etc.

… o regrese a la API antigua y use solo el GPS, que es lo que decidí hacer hasta que Google mejore la API fusionada.

La API de servicios de ubicación de Google , parte de los servicios de Google Play, proporciona un marco de alto nivel más poderoso que maneja automáticamente los proveedores de ubicación , el movimiento del usuario y la precisión de la ubicación . También maneja la progtwigción de actualización de ubicación en función de los parámetros de consumo de energía que proporcione. En la mayoría de los casos, obtendrá un mejor rendimiento de la batería , así como una precisión más apropiada, mediante la API de servicios de ubicación.

Aquí se pueden encontrar las diferencias más detalladas entre las dos API de Google Play Service Location API y Android Framework Location API.