SDK de Android: Construir una aplicación buscadora de Centros Comerciales - Mapa y ubicación
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Este tutorial explorará cómo utilizar la API de Google Maps para superponer puntos de interés (POI) y utilizar los Servicios basados en la ubicación disponibles en su teléfono para mostrar su posición relativa a las ubicaciones de POI disponibles. En este caso, utilizaremos Shopping como POI.
He dividido esta lección en dos partes. La Parte 1 (la lección presentada en este tutorial) cubrirá:
- Usando el objeto MapView
- Usando su huella dactilar MD5 para obtener una clave API para usar Google Maps
- Implementación de un servicio de ubicación LocationListener para obtener su ubicación actual
La Parte 2 cubrirá:
- Usar bibliotecas externas en su aplicación
- Crear superposiciones para representar su ubicación actual y varios puntos de interés
¡Comencemos ahora!
Paso 1: crea un nuevo proyecto de Android
Inicie el IDE de Eclipse y cree un nuevo proyecto de Android.
Para hacer esto dentro del IDE de Eclipse, vaya a: File > Create > New Android Project (Archivo > Crear > Nuevo proyecto de Android)
Crea el nuevo proyecto con la siguiente configuración:
Nombre del proyecto: MallFinder
Objetivo de compilación: Plataforma de API de Google: nivel 7 de API 2.1
Nombre de la aplicación: Mall Finder
Nombre del paquete: com.shawnbe.mallfinder
Crear actividad: MallFinderActivity
MinimumSDK: 7


Después de configurar las configuraciones, haga clic en finalizar.
Paso 2: Registrarse con Google para clave de API
Dado que los objetos MapView utilizan Google Maps, debe registrarse en Google para obtener una clave API y aceptar los Términos del servicio antes de poder utilizarlos. Este proceso es bastante simple e indolora y realizaremos este proceso paso a paso. Para obtener más información, consulte este enlace sobre Obtención de una clave API de Maps.
Para generar una clave API, se requiere su huella digital MD5 del certificado que usará para firmar su aplicación. Suena confuso, lo sé, pero no es tan difícil como suena, como descubrirás mientras recorremos los diferentes pasos. En lugar de utilizar el método de solicitud de comando para obtener su huella dactilar MD5 como se describe en el enlace anterior, utilizaremos un complemento de keytool para Eclipse. Para obtener más información sobre el complemento de keytool, visite este sitio web.
Paso 3: instalar el complemento Keytool
Mientras está en el IDE de Eclipse, vaya a Help > Install New Software (Ayuda > Instalar nuevo software).


Cuando aparezca la nueva ventana, haga clic en el botón "Add" ("Agregar") en la parte superior de la ventana.
Ingrese "keytool" (sin comillas) en el campo de nombre y
http://www.keytool.sourceforge.net/update en el campo de ubicación.


Haga clic en OK.
Después de un corto tiempo de carga, aparecerá una casilla de verificación con la etiqueta "keytool" en la ventana emergente. Seleccione la casilla de verificación y haga clic en Siguiente. Revise los términos del acuerdo de licencia y luego haga clic en Siguiente para finalizar.
Nota: Durante la instalación, se le puede pedir que determine si confía en los certificados de seguridad. Si lo hace, seleccione la casilla de verificación y haga clic en Aceptar para continuar con la instalación.


Después de la instalación, se le pedirá que reinicie Eclipse. Hazlo y continúa.
Paso 4: Obtener la huella dactilar MD5
Después de reiniciar Eclipse, debería ver un nuevo elemento de menú, "Keytool", con un pequeño icono de llave al lado.


Ahora vamos a abrir el almacén de claves de depuración. Nota: la ubicación puede variar según su sistema operativo. Las ubicaciones predeterminadas para varios sistemas operativos son
- Windows Vista : C:\Users\<user>\.android\debug.keystore
- Windows XP : C:\Documents and Settings\<user>\.android\debug.keystore
- OS X and Linux : ~/.android/debug.keystore
Haga clic en el elemento del menú de Keytool y abrir el almacén de claves.
Haga clic en el botón Examinar ubicado a la derecha del cuadro de texto Nombre de archivo y vaya a la ubicación del almacén de claves de depuración (ubicación predeterminada más arriba) y seleccione el archivo debug.keystore.
Haga clic en Open (Abrir) y escriba "android" (sin las comillas), que es la contraseña de depuración predeterminada y luego haga clic en Load (Cargar).


Una nueva pestaña Keytool ahora debería estar visible en el panel inferior de la pantalla (si no la ve, vaya a Window > Open Perspective > Java Browsing (Ventana> Abrir perspectiva> Navegación Java)).


Haga clic en la flecha pequeña a la izquierda de la ruta de debug.keystore para mostrar androiddebugkey.
Haga doble clic en androiddubugkey y copie la huella dactilar MD5.
Abra su navegador web y vaya a la siguiente URL. http://code.google.com/android/maps-api-signup.html
Lea los términos y condiciones, y si está de acuerdo, ingrese la huella digital MD5 en el campo de texto y haga clic en "Generar clave de API". Tome nota de su clave API ya que esto es necesario para que MapView funcione.
Paso 5: agrega MapView al diseño
En este paso, agregaremos un MapView al archivo de diseño.
Abra el archivo main.xml ubicado en MallFinder > res > layout > main.xml y actualice el archivo para incluir FrameLayout y MapView como se muestra a continuación:
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
android:layout_width="fill_parent" |
5 |
android:layout_height="fill_parent" |
6 |
android:orientation="vertical" > |
7 |
<FrameLayout
|
8 |
android:layout_width="fill_parent" |
9 |
android:layout_height="fill_parent"> |
10 |
<com.google.android.maps.MapView
|
11 |
android:id="@+id/mapView" |
12 |
android:layout_width="fill_parent" |
13 |
android:layout_height="fill_parent" |
14 |
android:clickable="true" |
15 |
android:apiKey="PUT YOUR API KEY HERE"/> |
16 |
</FrameLayout>
|
17 |
</LinearLayout>
|
El diseño anterior crea una vista de mapa en todo el espacio de pantalla disponible. Antes de que podamos seguir adelante y ejecutar la aplicación para ver MapView, hay varios pasos más para completar. Ejecutar la aplicación en su estado actual dará como resultado un cierre forzado.
Paso 6: configurar los permisos y declarar las bibliotecas requeridas
Como nuestra aplicación descargará datos de Google Maps y también necesita acceder a la información del GPS del teléfono u otros servicios basados en la ubicación, necesitaremos solicitar los permisos necesarios para utilizar estos servicios y características en el archivo de manifiesto de Android.
Para hacerlo, abra el archivo de manifiesto de Android ubicado en MallFinder > AndroidManifest.xml.
Agregue las siguientes líneas después de la etiqueta de cierre de la application (</application>) pero antes de la etiqueta de cierre del manifest (</manifest>).
1 |
|
2 |
<uses-feature android:name="android.hardware.location.gps"/> |
3 |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> |
4 |
<uses-permission android:name="android.permission.INTERNET"/> |
En este ejemplo, no necesitaré FINE_LOCATION, pero he incluido esto aquí, ya que imagino que es posible que desee realizar ajustes en el código para probar los diferentes proveedores. Si desea obtener la ubicación más precisa, necesitará los permisos de FINE_LOCATION. Por lo general, como regla para cualquier aplicación de producción, no debe solicitar permisos que no necesita. Esta es una práctica muy mala y hace que el usuario desconfíe de su aplicación a medida que solicita más permisos. Si no tiene intención de utilizar los proveedores más precisos, puede ajustar el permiso a android.permission.ACCESS_COARSE_LOCATION.
Para utilizar Google Maps en nuestro MapView, debemos declarar la biblioteca en nuestro archivo Manifest, así que hagámoslo también agregando el siguiente código entre la etiqueta de actividad de cierre y la de cierre:
1 |
|
2 |
<uses-library android:required="true" android:name="com.google.android.maps" /> |
Como ya estamos en el archivo de Manifiesto de Android, eliminemos la barra de título ya que esto es innecesario. Usa demasiado de nuestro espacio de pantalla limitado. Para eliminarlo, agregue la línea siguiente dentro de la etiqueta de la aplicación:
1 |
|
2 |
android:theme="@android:style/Theme.NoTitleBar" |
Eso es todo por la edición de nuestro archivo Manifest, por lo que nuestro archivo manifiesto completo ahora se ve así:
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
package="com.shawnbe.mallfinder" |
5 |
android:versionCode="1" |
6 |
android:versionName="1.0" > |
7 |
<uses-sdk android:minSdkVersion="7" /> |
8 |
<application
|
9 |
android:icon="@drawable/ic_launcher" |
10 |
android:label="@string/app_name" |
11 |
android:theme="@android:style/Theme.NoTitleBar"> |
12 |
<activity
|
13 |
android:label="@string/app_name" |
14 |
android:name=".MallFinderActivity" > |
15 |
<intent-filter > |
16 |
<action android:name="android.intent.action.MAIN" /> |
17 |
|
18 |
<category android:name="android.intent.category.LAUNCHER" /> |
19 |
</intent-filter>
|
20 |
</activity>
|
21 |
<uses-library android:required="true" android:name="com.google.android.maps" /> |
22 |
</application>
|
23 |
<uses-feature android:name="android.hardware.location.gps"/> |
24 |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> |
25 |
<uses-permission android:name="android.permission.INTERNET"/> |
26 |
</manifest>
|
Paso 7: Configurando MapView
Antes de que podamos ver el MapView en acción, debemos hacer un par de ajustes en la clase MallFinderActivity.
Abra la clase de actividad principal (MallFinderActivity.java), que se encuentra en:
MallFinder > src > com.shawnbe.mallfinder > MallFinderActivity.class
En nuestra aplicación, necesitamos esta clase para extender MapActivity en lugar de Activity para que MapView funcione.
Actualiza la línea:
1 |
|
2 |
public class MallFinderActivity extends Activity { |
a:
1 |
|
2 |
public class MallFinderActivity extends MapActivity { |
Al ampliar la clase MapActivity, debemos implementar el método isRouteDisplayed(), por lo que también debemos agregar el siguiente método de esqueleto:
1 |
|
2 |
@Override
|
3 |
protected boolean isRouteDisplayed() { |
4 |
// TODO Auto-generated method stub
|
5 |
return false; |
6 |
}
|
En este punto, podemos iniciar la aplicación y mostrar el MapView, pero establezcamos un par de opciones, como el nivel de zoom y las capas visibles. Comenzamos declarando las siguientes variables antes del método onCreate:
1 |
|
2 |
private MapController mapController; |
3 |
private MapView mapView; |
Agregue las siguientes líneas de código al método onCreate.
1 |
|
2 |
mapView = (MapView)findViewById(R.id.mapView); |
3 |
mapView.setBuiltInZoomControls(true); |
4 |
mapView.setSatellite(false); |
5 |
mapView.setStreetView(true); |
6 |
mapController = mapView.getController(); |
7 |
mapController.setZoom(13); |
El código anterior muestra solo la capa Calle y oculta la capa Satélite. He elegido esto como una preferencia personal, ya que me resulta más fácil de leer en este formato. Siéntase libre de ajustar esto como lo considere conveniente cambiando los valores booleanos falsos y verdaderos. Además, el nivel de zoom se establece en 13, sin embargo, esto también puede ajustarse, siendo 1 una vista del mundo completa y 20 el zoom máximo.
Finalmente, podemos continuar e iniciar la aplicación para garantizar que todo funcione como se espera hasta este momento.
Hay varias formas de ejecutar la aplicación, la primera:
Haga clic derecho en el Proyecto en la ventana del Package Explorer > Run as > Android Application (Explorador de paquetes> Ejecutar como> Aplicación de Android)
O:
Desde el menú, haga clic en Run > Run (Ejecutar> Ejecutar)


Luego selecciona tu teléfono o emulador. Debería ver un mapa que cubra toda su pantalla, excepto la barra de notificaciones en la parte superior de la pantalla, así como poder desplazarse y con ambos dedos para acercar.


Paso 8: Obteniendo tu ubicación actual
Para obtener su ubicación actual, usamos la clase locationManager, que permite que la aplicación obtenga la ubicación del dispositivo. Este proceso puede llevar un tiempo para obtener una solución en la ubicación actual, por lo tanto, un enfoque recomendado es utilizar su última ubicación conocida lastKnownLocation hasta que pueda obtener una solución más precisa en su ubicación actual.
Declare dos variables más justo debajo de las que declaramos en el paso 7 anterior:
1 |
|
2 |
private LocationManager locationManager; |
3 |
private GeoPoint currentLocation; |
Además, agregue los siguientes métodos a la clase MallFinderActivity.java:
1 |
|
2 |
public void getLastLocation(){ |
3 |
String provider = getBestProvider(); |
4 |
currentLocation = locationManager.getLastKnownLocation(provider); |
5 |
if(currentLocation != null){ |
6 |
setCurrentLocation(currentLocation); |
7 |
}
|
8 |
else
|
9 |
{
|
10 |
Toast.makeText(this, "Location not yet acquired", Toast.LENGTH_LONG).show(); |
11 |
}
|
12 |
}
|
13 |
|
14 |
public void animateToCurrentLocation(){ |
15 |
if(currentPoint!=null){ |
16 |
mapController.animateTo(currentPoint); |
17 |
}
|
18 |
}
|
19 |
|
20 |
public String getBestProvider(){ |
21 |
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); |
22 |
Criteria criteria = new Criteria(); |
23 |
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); |
24 |
criteria.setAccuracy(Criteria.NO_REQUIREMENT); |
25 |
String bestProvider = locationManager.getBestProvider(criteria, true); |
26 |
return bestProvider; |
27 |
}
|
28 |
|
29 |
public void setCurrentLocation(Location location){ |
30 |
int currLatitude = (int) (location.getLatitude()*1E6); |
31 |
int currLongitude = (int) (location.getLongitude()*1E6); |
32 |
currentLocation = new GeoPoint(currLatitude,currLongitude); |
33 |
|
34 |
currentLocation = new Location(""); |
35 |
currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6); |
36 |
currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6); |
37 |
}
|
Agregue las siguientes dos líneas al final del método onCreate:
1 |
|
2 |
getLastLocation(); |
3 |
animateToCurrentLocation(); |
El método onCreate ahora se ve así:
1 |
|
2 |
public void onCreate(Bundle savedInstanceState) { |
3 |
super.onCreate(savedInstanceState); |
4 |
setContentView(R.layout.main); |
5 |
mapView = (MapView)findViewById(R.id.mapView); |
6 |
mapView.setBuiltInZoomControls(true); |
7 |
mapView.setSatellite(false); |
8 |
mapView.setStreetView(true); |
9 |
mapController = mapView.getController(); |
10 |
mapController.setZoom(13); |
11 |
getLastLocation(); |
12 |
animateToCurrentLocation(); |
13 |
}
|
El método getLastLocation crea una instancia de la clase locationManager y, según los requisitos, determina cuál es el mejor proveedor para usar en los servicios de ubicación. En el código anterior, no especificamos ningún criterio para el proveedor, sin embargo, puede ajustar los criterios en función de su precisión y requisitos de energía mediante los métodos criteria.setAccuracy() y criteria.setPowerRequirement(). En el Paso 6 anterior, mencioné que es posible que desee ajustar sus criterios para obtener la ubicación más precisa. Si quisiera hacer esto, establecería los criterios de precisión en ACCURACY_FINE y la línea de código se vería así:
1 |
|
2 |
criteria.setAccuracy(Criteria.ACCURACY_FINE); |
La razón por la que no elegí el proveedor más preciso (que es GPS) es porque estaría probando este código en interiores y es posible que nunca bloquee mi posición, pero siéntase libre de probarlo por sí mismo, cambie la precisión y salga a la calle y vea si puede obtener un bloqueo de GPS en su posición actual.
Dependiendo de los criterios especificados, su teléfono puede usar diferentes proveedores, esto es usualmente GPS o red (pero puede ser diferente). La última ubicación conocida se establece como la ubicación actual al menos hasta que obtengamos una ubicación más precisa y actualizada. La latitud y la longitud de la ubicación actual se encuentran y animamos o desplazamos el mapa para centrarnos en esas coordenadas.
Ahora que tenemos la última posición conocida, usamos el detector de ubicación para detectar cambios en nuestra ubicación y actualizar la aplicación a medida que ocurren estos cambios. Para hacer esto necesitamos nuestra clase de actividad (MallFinderActivity.java) para implementar locationListener. Primero actualizamos la línea:
1 |
|
2 |
public class MallFinderActivity extends MapActivity { |
A:
1 |
|
2 |
public class MallFinderActivity extends MapActivity implements LocationListener{ |
Implementar el oyente de ubicación requiere que anulemos un par de métodos, por lo que agregamos los siguientes métodos barebone a continuación (cuando me refiero a esqueleto o métodos barebone, me refiero a que se crea el shell para los métodos, pero en realidad no hacen nada en esta vez):
1 |
|
2 |
@Override
|
3 |
public void onLocationChanged(Location arg0) { |
4 |
// TODO Auto-generated method stub
|
5 |
}
|
6 |
|
7 |
@Override
|
8 |
public void onProviderDisabled(String arg0) { |
9 |
// TODO Auto-generated method stub
|
10 |
}
|
11 |
|
12 |
@Override
|
13 |
public void onProviderEnabled(String arg0) { |
14 |
// TODO Auto-generated method stub
|
15 |
}
|
16 |
|
17 |
@Override
|
18 |
public void onStatusChanged(String arg0, int arg1, Bundle arg2) { |
19 |
// TODO Auto-generated method stub
|
20 |
}
|
Utilizaremos el método onLocationChanged para detectar cualquier actualización en nuestra ubicación y luego establecer esto como nuestra ubicación actual utilizando el método setcurrentLocation.
Actualice el método onlocationChanged para reflejar lo siguiente:
1 |
|
2 |
@Override
|
3 |
public void onLocationChanged(Location newLocation) { |
4 |
// TODO Auto-generated method stub
|
5 |
setCurrentLocation(newLocation); |
6 |
}
|
Agregue las siguientes líneas de código. Estos métodos solicitan actualizaciones cada segundo cuando se inicia o reanuda la aplicación y también deja de buscar actualizaciones cuando la aplicación se detiene o se cancela.
1 |
|
2 |
@Override
|
3 |
protected void onResume() { |
4 |
super.onResume(); |
5 |
locationManager.requestLocationUpdates(getBestProvider(), 1000, 1, this); |
6 |
}
|
7 |
|
8 |
@Override
|
9 |
protected void onPause() { |
10 |
super.onPause(); |
11 |
locationManager.removeUpdates(this); |
12 |
}
|
Si ejecuta la aplicación en este punto, MapView debe centrarse en su última ubicación conocida, y cuando su teléfono pueda obtener una solución, se actualizará para centrarse alrededor de su ubicación actual. Dependiendo de los criterios de precisión establecidos en el Paso 7, el tiempo para corregir su ubicación variará. En esta lección, hemos aprendido cómo usar MapView, implementar el locateListener y obtener su ubicación actual. En la próxima lección, ampliaremos esto e incluiremos una biblioteca externa para manejar las superposiciones en MapView y mostrar información en globos emergentes cuando se toquen los distintos puntos de interés.



