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 interfaz LocationListener 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.