Android: integrando Google Maps con el GPS

Luego del post anterior donde vimos como usar google maps en nuestra aplicación vamos a integrar el GPS haciendo que nuestro mapa nos muestre “nuestra” posición.

Escuchando al GPS

AndroidManifiest.xml

Primero debemos agregar los permisos para obtener la ubicación “fina”, es decir, mediante el GPS, para esto agregamos el permiso ACCESS_FINE_LOCATION debajo del permiso que ya tenemos.

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

MyGoogleMapsActivity

En la línea 16 estamos referenciando el objeto del mapa, en la 17 estamos referenciando al servicio de sistema de localización (LocationManager) y en la línea 18 estamos diciéndole al locationManager que escuche las actualizaciones del de localización producidas por el GPS con una instancia del listener MyLocationListener.

   1: package com.neluz.MyGoogleMaps;
   2:  
   3: import com.google.android.maps.MapActivity;
   4: import com.google.android.maps.MapView;
   5:  
   6: import android.content.Context;
   7: import android.location.LocationManager;
   8: import android.os.Bundle;
   9:  
  10: public class MyGoogleMapsActivity extends MapActivity {
  11:     @Override
  12:     public void onCreate(Bundle savedInstanceState) {
  13:         super.onCreate(savedInstanceState);
  14:         setContentView(R.layout.main);
  15:         
  16:         MapView mapView = (MapView) findViewById(R.id.mapview);
  17:         LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  18:         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, 
  19:                 new MyLocationListener(mapView.getController(), locationManager, getBaseContext()));
  20:  
  21:         mapView.setBuiltInZoomControls(true);
  22:     }
  23:  
  24:     @Override
  25:     protected boolean isRouteDisplayed() {
  26:         return false;
  27:     }
  28: }

en la línea 21 estamos habilitando el control de zoom en el mapa, esto no es necesario para el uso de GPS, pero va mejorando nuestra aplicación.

MyLocationListener

Creamos la clase MyLocationListener implementando LocationListener y en el método onLocationChanged es donde vamos a posicionar el mapa en la nueva ubicación, para esto creamos el GeoPoint a partir de las coordenadas de la nueva localización (líneas 34 a 36) y le pedimos al controller del mapa que lo posicione en las nuevas coordenadas (línea 38). Luego hacemos zoom en esta ubicación (línea 39).

   1: package com.neluz.MyGoogleMaps;
   2:  
   3: import android.content.Context;
   4: import android.location.Location;
   5: import android.location.LocationListener;
   6: import android.location.LocationManager;
   7: import android.os.Bundle;
   8: import android.widget.Toast;
   9:  
  10: import com.google.android.maps.GeoPoint;
  11: import com.google.android.maps.MapController;
  12: import com.google.android.maps.MapView;
  13:  
  14: public class MyLocationListener implements LocationListener {
  15:     private Context context;
  16:     private LocationManager locationManager;
  17:     private MapController mapController;
  18:  
  19:     public MyLocationListener(MapController mapController, LocationManager locationManager, Context context)
  20:     {
  21:         this.mapController = mapController;
  22:         this.locationManager = locationManager;
  23:         this.context = context;
  24:     }
  25:     
  26:     @Override
  27:     public void onLocationChanged(Location loc) {
  28:         Toast.makeText(context, "onLocationChanged", Toast.LENGTH_SHORT).show();
  29:         
  30:         if (loc!=null) {
  31:             Toast.makeText(context, 
  32:                     "Location changed : Lat: " + loc.getLatitude() + " Lng: " + loc.getLongitude(), Toast.LENGTH_SHORT).show();
  33:             
  34:                 GeoPoint p = new GeoPoint(
  35:                         (int) (loc.getLatitude() * 1E6), 
  36:                         (int) (loc.getLongitude() * 1E6));
  37:  
  38:                 mapController.animateTo(p);
  39:                 mapController.setZoom(12);
  40:         }
  41:         else
  42:         {
  43:             Toast.makeText(context, "location changed to null value", Toast.LENGTH_SHORT).show();
  44:         }
  45:         
  46:         // por el emulador??
  47:         locationManager.removeUpdates(this);
  48:         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, 
  49:                 new MyLocationListener(mapController, locationManager, context));
  50:     }
  51:  
  52:     @Override
  53:     public void onProviderDisabled(String arg0) {
  54:         Toast.makeText(context, "Provider Disabled", 
  55:                 Toast.LENGTH_SHORT).show();
  56:     }
  57:  
  58:     @Override
  59:     public void onProviderEnabled(String arg0) {
  60:         Toast.makeText(context, "Provider Enabled", 
  61:                 Toast.LENGTH_SHORT).show();
  62:  
  63:  
  64:     }
  65:  
  66:     @Override
  67:     public void onStatusChanged(String provider, int status, Bundle arg2) {
  68:         Toast.makeText(context, "Status on " + provider + " is " +  getStatusMessage(status), 
  69:                 Toast.LENGTH_SHORT).show();
  70:     }
  71:  
  72:     private String getStatusMessage(int status) {
  73:         // TODO Auto-generated method stub
  74:         if (status == 1)
  75:             return "contecting";
  76:         else if (status == 2)
  77:             return "conected";
  78:         return "unknown";
  79:     }
  80:  
  81: }

las líneas 47 a 49 no estoy seguro que sean necesarias, pero el emulador de posiciones no funciona sino reiniciamos el listener.

Simulando posiciones

Algo que probablemente queramos hacer es simular distintas posiciones de nuestro Android como si estuviésemos en esos lugares (o moviéndonos). Para esto me encontré con una limitación que les cuento a continuación y dos alternativas para solucionarlo.

Una limitación y dos solución

Una gran “limitación” en el “Emulator Console” ya sea el integrado con Eclipse como el que se ejecuta desde DDMS es que requieren que la configuración regional esté en formato inglés de estados unidos. Así que o bien cambian la configuración regional de sus PCs o bien usan la terminal telnet, yo me quedé con esta segunda opción (aunque probé y ambas funcionan).

Si ustedes desarrollan todo como está en este post y al enviarle coordenadas al Android, el gps cambia de estado pero nunca se ejecuta el evento onLocationChanged es por este problema.

Simulando posiciones con telnet

Ejecutamos el comando telnet localhost 5554, donde 5554 es el puerto del AVD (Android Virtual Devices) donde están emulando el Android. Luego, con el comando geo fix simulamos datos del GPS.

image
iniciamos telnet

image

image
Iniciamos el emulador

image

ejecutamos el comando:

geo fix -58.433533 -34.615127

image

Nuestra aplicación debe navegar hasta esta ubicación, en la ciudad de Buenos Aires.

Luego podemos ir a:

  • geo fix –69.18 –16.01 (Isla del Sol en Bolivia)
  • geo fix –3.59 37.18 (Granada en España)
  • y todo un planeta para navegar

9 comentarios:

  1. Un tutorial EXCELENTE!! muchas gracias

    ResponderBorrar
  2. Disculpe porque el google maps de mi aplicacion solo se ve en el emulador de la computadora pero en un android real no se puede ver, solo sale el marcado y el mapa no sale , le agradeceria mucho si me dice por favor.

    ResponderBorrar
  3. Katerine, dale una mirada al post anterior que habla del problema de los mapas en blanco y las keys. Espero te ayude a solucionar el problema.

    ResponderBorrar
  4. Hola el tutorial es excelente, m gustaria saber si es posible guardar las coordenadas en una base de datos y como puedo hacerlo?. Gracias!

    ResponderBorrar
  5. Ana, si, se puede... podrías tomar las coordenadas del GPS tal cual se hace en onLocationChanged y guardarlas en una db, por ejemplo de sqlite. Te dejo un link de sqlite: http://developer.android.com/reference/android/database/sqlite/package-summary.html

    ResponderBorrar
  6. Hola otra vez! Mi problema es que onLocationChanged es un metodo predefinido como void por lo que no puedo retornar los valores de la latitud y longitud, o bueno no se como hacerlo, puedes ayudarm???

    ResponderBorrar
  7. Lo que tengas que hacer, hacelo dentro del método onLocationChanged. En lugar de mapController.animateTo(p); para mover el mapa a esa ubicación, podés hacer algo como db.Save(p); o lo que necesites.

    ResponderBorrar
  8. Este comentario ha sido eliminado por el autor.

    ResponderBorrar
  9. GRACIAS x tu ayuda, m ha servido d mucho!! :) Ojala publiques mas posts sobre android, para q los q somos primerisos en esto, aprendamos un poco mas!! Excelente tutorial!

    ResponderBorrar