Maps & Location
La manera más sencilla de trabajar con mapas en Android, es usando Google Maps. Incluso el wizard nos resuleve gran parte del trabajo, asi que comencemos creando una app con un Mapa desde el Wizard de Android Studio.
Analicemos el código que se genera automáticamente antes de seguir avanzando.
Al igual que cualquier otra plantilla, el Wizard nos creó su Activity y su Layout. Pero además vamos a ver que:
MANIFIESTO:
RECURSO DE VALOR
GRADLE:
La meta-data es básicamente una manera de almacenar información de nuetra app que se puede acceder desde cualquier parte de ella. Para ello debe estar dentro de <application> pero fuera de una <activity>.
<meta-data android:name="mi_nombre" android:value="SebaS" />
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(),
PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
String miNombre = bundle.getString("mi_nombre");
Y luego lo accedemos de la siguiente manera:
La ventaja más grande frente a un recurso de String es que no necesita del Contexto para accederlo
Lancemos la app y probemos tanto nuestra propia meta-data como el Mapa de Google Maps.
Psst... Veamos los Logs para más información
Lancemos la app y probemos tanto nuestra propia meta-data como el Mapa de Google Maps.
Psst... Veamos los Logs para más información
La razón por la que no vemos el mapa es porque no tenemos una API Key válida. Este es un mecanismo que utiliza Google para controlar el acceso y el uso de sus mapas y cada aplicación debe tener una.
Si bien se puede usar una única key para todas las aplicaciones, por cuestiones de seguridad se recomienda vincular cada API Key a un única app
1- Solicitar API Key
Debemos ingresar en Google Developer Console
2- Crear un Proyecto Nuevo
3- Ingresar en Enable APIS & Services
4- Dentro de GoogleMapsApi buscamos Google Maps Android API
5- Clickeamos en ENABLE
6- Creamos Credenciales
7- Seleccionamos que tipo de Credencial
8- Restringir Credencial por aplicacion Android
9- Ingresamos el nombre del paquete
10- Ingresar Firma Digital (la optenemos el recursor que creo el wizard)
11- Copiamos la KEY en ese recurso
12- Puede demorar hasta 5min en activarse
Comencemos por cambiar a una AppCompatActivity en lugar de FragmentActivity.
Y agreguemos un RelativeLayout al layout para poder agregar botones en la parte inferior del mapa
Y vamos a agregar una botonera para configurar el mapa
Los atributos que vamos a ver son:
Agreguemos un boton que modifique cada opcion
Vamos a ver como podemos agregar un marcador presionando en el mapa. Para ellos necesitamos escuchar a los eventos de LongClick y si el marcador no existe, crearlo y si existe actualizar su posición
Posicion Actual
El dispositivo puede obtener la posición de varias fuentes: GPS, WiFi, Celular.
Vamos a seguir usando los servicios de Google que nos abstraen de la fuente y nos dicen cuál es la última posición conocida del dispositivo.
Nuevamente agregamos la dependencia en el Gradle
compile 'com.google.android.gms:play-services-location:10.2.6'
Esto nos permite crear un objecto GoogleApiClient que se encarga de manejar las solicitudes de posición
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle) {
myLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (myLocation != null){
LatLng newPos = new LatLng(myLocation.getLatitude(), myLocation.getLongitude());
myMarker.setPosition(newPos);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newPos,17));
}
}
@Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
})
.addOnConnectionFailedListener()
})
.addApi(LocationServices.API)
.build();
Como estamos apuntando a una API superior de Android, hay permisos considerados peligrosos a los cuales debemos pedir autorización explicita del usuario en tiempo de ejecucion. El acceso a la ubicación es uno de ellos y por eso es necesario solicitar el permiso.
Esto implica:
Chequear si estoy autorizado y mostrar dialogo
private void solicitarPermisoGPS (){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_GPS);
} else {
// YA ESTOY AUTORIZADO
}
}
Capturar respuesta del Usuario
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSIONS_REQUEST_GPS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(getApplicationContext(), "Sin permiso no se puede usar la app",
Toast.LENGTH_LONG).show();
finish();
}
}
}
}
Y finalmente nos conectamos y desconectamos del Cliente al iniciar la App y terminarla (onStart y onStop)
Y otra cosa que podemos hacer ahora es habilitar la Localizacion desde el Mapa para que nos muestre el icono de MyLocation
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(false);
}
Actualiazación de Posición
Esto es muy similar a lo que ya hicimos, sólo que ahora le vamos a decir a Google que queremos que nos avise cuando hay un cambio en la posición. Esto es un LocationRequest, un objeto que debemos crear:
locationRequest = new LocationRequest();
locationRequest.setInterval(CADA_10seg);
locationRequest.setFastestInterval(CADA_5seg);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
FastInterval es por si hay otra app usando los servicios de localizacion con un periodo mas corto, y la posición está disponible antes, podemos obtener esa posicion en nuestra app
Lo unico que nos falta decir es cuando queremos comenzar a recibir los cambios de posicion y cuando queremos dejar de hacerlo
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient,
locationRequest, MapsActivity.this);
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient,
MapsActivity.this);
Y ademas debemos implementar LocationListener en nuestra actividad para definir lo que queremos que haga cuando haya un cambio de posicion
Mock Location nos permite emular la posición de nuestro dispositivo, con el fin de que podamos testear nuestras aplicaciones que hacen uso del posicionamiento del dispositivo