Curso Android: Geolocalización y utilización de mapas de Google
En el quinto capítulo del Curso Android seguiremos trabajando con el hardware de los teléfonos, ahora nos corresponde aprovechar el GPS y mostrar la ubicación actual en un mapa. La aplicación que realizaremos nos permitirá mostrar la ubicación y actualizarse cada vez que exista movimiento.
Es importante notar que las pruebas de este capítulo al igual que los capítulos 4 y 5 son para realizarlas en un teléfono con Android es posible utilizar el emulador con algunos arreglos. Ejemplo: obtener localización, monitorear sus cambios y mostrarla en un mapa a través de markers. Queremos que al finalizar se vea de la siguiente form:
Disposición inicial
Iniciamos descargando el código que debe ser importado hacia un nuevo proyecto y que tiene algunas características importantes.
- Permisos en el Manifest, por el acceso a internet para el mapa y la ubicación del GPS requerimos estos 2 permisos bajo el tag:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- Uso de la librería de mapas, también en el Manifest bajo el tag:
<uses-library android:name="com.google.android.maps" />
- En la clase de la actividad principal, utilizaremos herencia de
MapActivity
para facilitarnos el manejo del mapa e implementaremos la interfazLocationListener
para detectar los cambios en la localización. - Por heredar de
MapActivity
debemos implementar el método:@Override protected boolean isRouteDisplayed() { return false; }
- Por implementar LocationListener debemos realizar los siguientes métodos:
@Override public void onLocationChanged(Location location) {} @Override public void onProviderDisabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {}
Diseño
Utilizaremos una vista especial para el mapa es necesario un key para la utilización del servicio de Google Maps y depende directamente del certificado utilizado para firmar las aplicaciones, el valor del atributo android:apiKey
que aparece en el código es válida para mi certificado.
<com.google.android.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:apiKey="0xJ4uwRGDV296srCn4Iiy46oFmd1jecLr07BsAA" />
Agregando código
La clase de la Activity
para nuestra aplicación extenderá de MapActivity
para facilitarnos el manejo de la visualización del mapa e implementará LocationListener
para el manejo de las actualizaciones de ubicación.
public class Main extends MapActivity implements LocationListener
De los métodos disponibles, utilizaremos onProviderDisabled
para forzar al usuario a tener el GPS funcionando antes de que la aplicación inicie.
@Override public void onProviderDisabled(String provider) { Intent intent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); }
Vamos a mostrar un marker
en las diferentes ubicaciones detectadas, para ello haremos una clase que represente este Overlay
mostrando la imagen seleccionada. Para este ejemplo se utilizará la imagen del ícono, al definirla dentro de la misma clase de la Activity
principal entonces será una clase privada.
class MyOverlay extends Overlay { }
Tendremos una variable de instancia representando el punto donde se colocará el marcador y será un parámetro recibido por el constructor:
GeoPoint point; /* El constructor recibe el punto donde se dibujará el marker */ public MyOverlay(GeoPoint point) { super(); this.point = point; }
Sobrecargaremos el método draw
para dibujar nuestro marker
:
@Override public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { super.draw(canvas, mapView, shadow); //se traduce el punto geo localizado a un punto en la pantalla Point scrnPoint = new Point(); mapView.getProjection().toPixels(this.point, scrnPoint); //se construye un bitmap a partir de la imagen Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.icon); //se dibuja la imagen del marker canvas.drawBitmap(marker, scrnPoint.x - image.getWidth() / 2, scrnPoint.y - marker.getHeight() / 2, null); return true; }
El código completo de la clase para los overlays
es el siguiente:
class MyOverlay extends Overlay { GeoPoint point; //El constructor recibe el punto donde se dibujará el marker public MyOverlay(GeoPoint point) { super(); this.point = point; } @Override public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { super.draw(canvas, mapView, shadow); //se traduce el punto geolocalizado a un punto en la pantalla */ Point scrnPoint = new Point(); mapView.getProjection().toPixels(this.point, scrnPoint); //se construye un bitmap a partir de la imagen Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.icon); // se dibuja la imagen del marker canvas.drawBitmap(marker, scrnPoint.x - marker.getWidth() / 2, scrnPoint.y - marker.getHeight() / 2, null); return true; } }
Para ir dibujando estos markers al principio y cada vez que haya una actualización de la ubicación, utilizaremos un método nuevo con la firma:
protected void updateLocation(Location location)
Obtenemos el MapView
y de él un MapController
:
MapView mapView = (MapView) findViewById(R.id.mapview); MapController mapController = mapView.getController();
Construimos un punto a partir de la latitud y longitud del Location
recibido:
GeoPoint point = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() * 1E6));
Movemos el centro del mapa hacia esta ubicación:
mapController.animateTo(point); mapController.setZoom(15);
Posterior a esto, intentaremos hacer geolocalización del punto, obtener una dirección a partir de las coordenadas del punto. Primero instanciamos un objeto Geocoder
que responderá de acuerdo a la localidad configurada en el teléfono.
Geocoder geoCoder = new Geocoder(this, Locale.getDefault());
A través de este Geocoder
y con el punto de la ubicación intentamos obtener alguna dirección asociada y se lo hacemos saber al usuario por medio de un toast
(aviso).
try { List<Address> addresses = geoCoder.getFromLocation(point.getLatitudeE6() / 1E6, point.getLongitudeE6() / 1E6, 1); String address = ""; if (addresses.size() > 0) { for (int i = 0; i < addresses.get(0).getMaxAddressLineIndex(); i++) address += addresses.get(0).getAddressLine(i) + "\n"; } Toast.makeText(this, address, Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); }
Por último, instanciamos la clase MyOverlay
construída previamente para agregar un nuevo marker en el listado de overlays del mapa e invalidamos la vista para que vuelva a dibujarse todo.
List<Overlay> mapOverlays = mapView.getOverlays(); MyOverlay marker = new MyOverlay(point); mapOverlays.add(marker); mapView.invalidate();
En el método onCreate
vamos a instanciar un LocationManager
para mostrar el primer marker y solicitar actualizaciones:
MapView mapView = (MapView) findViewById(R.id.mapview); //habilitamos el control de zoom mapView.setBuiltInZoomControls(true); LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); updateLocation(locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)); /* se actualizará cada minuto y 50 metros de cambio en la localización mientras más pequeños sean estos valores más frecuentes serán las actualizaciones */ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 6000, 50, this);
Luego en el método onLocationChanged
llamamos a nuestro método updateLocation
para que dibuje un nuevo marker cada vez que se actualice la localización:
@Override public void onLocationChanged(Location location) { updateLocation(location); }
Descarga:
Puedes descargar el código de la aplicación completa y funcional en: Geolocalización y utilización de mapas de Google.
Conclusión
En este capítulo aprendimos sobre:
- Cómo manejar un mapa, la necesidad de una vista especial y solicitar un API Key.
- Cómo dibujar markers a través de overlays sobre el mapa, además personalizamos la imagen del marker.
- Cómo solicitar la ubicación actual y actualizaciones ante el cambio de ubicación.
Sería interesante profundizar un poco más y explicar cómo actualizar los contenidos de las capas (Overlay) en función del desplazamiento del usuario por el mapa. Cualquier aplicación que quiera usar MapView, necesita esta eso.
[…] Geolocalización y utilización de mapas de Google […]
[…] Geolocalización y utilización de mapas de Google […]
Hola, muy bueno el curso. He seguido todos los pasos y en el pc me va todo perfecto, pero al instalarlo en el movil, se me ve la pantalla blanca en el MapView, o sea, que no me descarga los mapas. ¿A qué puede ser debido?. Tengo activos los datos, el GPS, etc, me marca la posición, pero ya te digo que no sale el mapa.
Muchas gracias
Hola, muy bueno pero…
Para que versón de Android funcion??
Lo he probado en la versión 2.1 y 2.2 y en ninguna me manda mensaje de error ni nada.
De antemano gracias.
Saludos
Hola muy buenas noches, esta excelente todo lo que explicas, pero tengo una duda… bien,
Mi paquete se llama movistar.gps
y al principio de tu clase tu tienes estas importaciones:
import com.android.mdw.demo.Override;
import com.android.mdw.demo.R;
import com.android.mdw.demo.String;
import com.android.mdw.demo.Main.MyOverlay;
Bien, yo estoy pasando estas con el nombre de mi paquete…
import movistar.gps.R;
import movistar.gps.Envio.MyOverlay; (envío se llama mi clase)
Perfecto, esas dos van bien, pero:
import movistar.gps.String;
import movistar.gps.Override;
esas me dan error =( me dice que cree la clase STRING en el paquete movistar.gps y con .Override me dice exactamente lo mismo =(
Cabe destacar que donde estoy escribiendo la clase, no es la clase principal. es como mi 3era clase. ¿habrá algun problema? Porfa =( espero su ayuda.
Hola otra vez jaja, disculpa se me olvidó acotar algo. Pasé el proyecto que tu terminaste a mi Samsung Galaxy S I y me da error, cuando intento instalar dice: HAY UN PROBLEMA PARA ANALIZAR EL PAQUETE.
Disculpa solucionaste tu problema de ver el google maps de tu aplicacion android en un movil real? por favor si lo hiciste dimelo, ya no se q intentar.