lunes, 31 de diciembre de 2012

Comenzando con Google Maps API v2 parte 2



Desarrollo sobre la plataforma Android

Hola a todos, en este post vamos a hablar otra vez de Google Maps en Android, pero esta vez, no vamos a hablar de un tema exclusivo de la API v2 de Google Maps, ya que la versión 1 usa también estas estrategias para manejar la localización ;)
En un principio puede resultarnos complicado, cosas simples como por ejemplo obtener nuestra posición actual, algunas de las cosas que pueden hacer que nos resulte complicado, pueden ser:

  • Muchas fuentes de información: aunque parezca extraño esto, el tener múltiples fuentes de información (GPS, Wifi, 3G, Cell-ID), puede ocasionarnos el problema de no saber cual usar, o de configurar uno y no otro.
  • El cambio de posición: el saber como y cada cuanto se actualiza la posición.
  • Consumos de datos y energía: como deben imaginar también tenemos que tener en cuenta que de acuerdo a la manera en que tomemos estos datos, van a variar los consumos de estas cosas :P
Por suerte la librería de Android nos va a ayudar bastante con este tema, las dos cosas principales que vamos a necesitar van a ser dos objetos, uno de tipo LocationManager y el otro un listener de tipo LocationListener, un sencillo ejemplo podría ser:

// Tomamos la referencia hacia el manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Y aqui deberemos definir nuestro listener, para poder
// actualizar nuestra ubicacion
LocationListener locationListener = new LocationListener() {
   
public void onLocationChanged(Location location) {
     
// Este es el metodo que mas nos va a interesar implementar

// ya que es el que nos va a dar nuestra ubicacion
     hacerUsoDeNuestraUbicacion(location);
   
}

// Estos otros metodos tambien deberiamos implementarlos
   
public void onStatusChanged(String provider, int status, Bundle

extras) {}
   
public void onProviderEnabled(String provider) {}

   
public void onProviderDisabled(String provider) {}
 
};
// Y aca registramos nuestro listener con el location manager, para
// poder ir tomando las actualizaciones de ubicacion
locationManager
.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

Así que a nuestro manager deberemos pasarle, cual va a ser el proveedor de ubicación, en este caso le pase NETWORK, pero tranquilamente podria ser el GPS, tambien podriamos registrar los dos proveedores ;) los otros dos parámetros que son números, van a manejar la frecuencia con la que se va a ir actualizando. Hay que pensar en hacerlo dependiendo de nuestras necesidades, porque podríamos hacerlo todo el tiempo, pero hay que tener en cuenta el consumo de recursos y batería :P
Una vez visto esto, vamos a tener que tener en cuenta los permisos necesarios en nuestra app, para que pueda utilizar la internet, gps o el medio que usemos para tomar los datos. Ya que si esto no lo plasmamos en el manifest, nos va a saltar un error al querer correr la aplicación.
Si van a utilizar la red y el GPS, van a necesitar agregar este permiso:

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

Ahora si solo van a usar la red, podrían usar este permiso:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
En el primer caso no se necesitan dos permiso, ya que ACCESS_FINE_LOCATION contiene los dos permisos.
Como dije antes, hay que tener cuidado con el tema de los consumos, aquí hay un gráfico del proceso para encontrar la ubicación:





Después de ver este gráfico, debemos pensar en cuando vamos a comenzar a escuchar, para obtener actualizaciones de la ubicación. Así que para no afectar los consumos, debemos ver si comenzamos a escuchar cuando arranca la app, o cuando sucede algún tipo de acción, y ver cuando se va a terminar la escucha. Hay que tener en cuenta el periodo de tiempo por el que va a estar escuchando, ya que lo podríamos hacer por periodos, pero tenemos que ver que esos periodos de tiempo sean lo suficientemente largos para que el dispositivo pueda encontrar el dato.



Una cosa a tener en cuenta es algo que puede ser útil, pero a su vez puede causar dolores de cabeza, la clase LocationManager tiene un método llamado getLastKnownLocation().Este método, utiliza la caché de la última ubicación recibida, no devuelve la posición actual, tampoco solicita una nueva posición al proveedor de localización, este método se limita a devolver la última posición que se obtuvo a través del proveedor que se le indique como parámetro. Y esta posición se pudo obtener hace pocos segundos, hace días, hace meses, o incluso nunca.Por eso hay que tener cuidado cuando se usa, al querer usar la posición devuelta por el método getLastKnownLocation().
Volviendo al tema anterior,  por eso debemos pensar bien cuando utilizar requestLocationUpdates() para tomar los datos, y cuando locationManager.removeUpdates(locationListener);
Para detener esa escucha del listener, y dejar así de consumir recursos. Otro tip:



  • Para reducir los consumos, y así no tener quejas de las personas que utilizan la aplicación, podría reducir la frecuencia con la que se actualiza la ubicación, seteando en el LocationProvider.
  • Y restringir a uno de todos los proveedores, GPS, NETWORK, también esto lo podemos setear eligiendo que LocationProvider utilizamos.

Antes de dar un pequeño ejemplo funcional sobre toda esta teoría :D queria comentarles, que con el emulador podemos similar el uso de GPS, es más para algunas cosas de este tipo, puede llegar a ser más útil, que un movil físico, ya que con archivos KML podremos simular recorridos: https://developers.google.com/kml/documentation/kml_tut?hl=es

public class NuestraUbicacion extends Activity implements LocationListener {
 
//  En la activity deberiamos creear los textview
 private TextView latituteText;
 
private TextView longitudeText;
 
private LocationManager locationManager;
 
private String proveedor;
/** En este caso implementamos directamente en la clase el LocationListener  y heredamos de Activity */
 
@Override
 
public void onCreate(Bundle savedInstanceState) {
   
super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
// tomamos la refencia de los textview
   latituteText = (TextView) findViewById(R.id.TextView1);
   longitudeText = (TextView) findViewById(R.id.TextView2);

   
// Tomamos el location manager
   locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
   
// Definimos un objeto del tipo criteria para que este elija cual locatioin provider nos
   
// conviene utilizar
   Criteria criteria =
new Criteria();
   proveedor = locationManager.getBestProvider(criteria, false);
   Location ubicacion = locationManager.getLastKnownLocation(proveedor);

   
// vemos si se inicializamos la ubicacion
   
if (location != null) {
     System.out.println("Proveedor  " + proveedor + " ha sido seleccionado.");
     onLocationChanged(ubicacion);
   }
else {
     latituteText.setText("Ubicacion no encontrada");
     longitudeText.setText("Ubicacion no encontrada");
   }
 }

 
/* actualizamos la ubicacion */
 
@Override
 
protected void onResume() {
   
super.onResume();
   locationManager.requestLocationUpdates(proveedor, 400, 1,
this);
 }

 
/* detenemos el listener  */
 
@Override
 
protected void onPause() {
   
super.onPause();
   locationManager.removeUpdates(
this);
 }

 
@Override
 
public void onLocationChanged(Location location) {
   
int lat = (int) (location.getLatitude());
   
int lng = (int) (location.getLongitude());
   latituteText.setText(String.valueOf(lat));
   longitudeText.setText(String.valueOf(lng));
 }

 
@Override
 
public void onStatusChanged(String provider, int status, Bundle extras) {
   
// metodo a sobreescribit del LocationListener

 }
// lanzamos un toast cuando es habilitado el proveedor
 
@Override
 
public void onProviderEnabled(String provider) {
   Toast.makeText(
this, "Habilitado el nuevo proveedor  " + proveedor,
       Toast.LENGTH_SHORT).show();

 }
// lanzamos un toast  cuando es deshabilitado el proveedor
 @Override
 
public void onProviderDisabled(String provider) {
   Toast.makeText(
this, "Disabled provider " + provider,
       Toast.LENGTH_SHORT).show();
 }
}

Otros post relacionados con el tema:
http://www.aprendiendodeandroidymas.com/2012/12/comenzando-con-google-maps-api-v2-parte.html
http://www.aprendiendodeandroidymas.com/2013/04/comenzando-con-google-maps-api-v2-parte.html

Documentación oficial:
http://developer.android.com/guide/topics/location/strategies.html
https://developers.google.com/maps/documentation/android/?hl=es
http://developer.android.com/guide/topics/location/index.html
https://developers.google.com/maps/documentation/android/?hl=es
https://developers.google.com/maps/documentation/android/reference/index?hl=es

Es todo por ahora, vimos cómo obtener nuestra localización, y utilizar los diferentes medios para el posicionamiento. En el próximo post, probablemente veamos, como agregar marcadores, y algunas cosas para dejar más vistoso nuestro mapa. Espero que les haya gustado :D


Saludos a todos, Gabriel E. Pozo