Cómo solicitar actualizaciones de ubicación

El uso adecuado de la información de ubicación puede beneficiar a los usuarios de tu app. Por ejemplo, si esta ayuda al usuario a orientarse mientras camina o conduce, o si realiza un seguimiento de la ubicación de objetos, necesita obtener la ubicación del dispositivo en intervalos periódicos. Además de la ubicación geográfica (latitud y longitud), tal vez quieras brindar al usuario más información, como el rumbo (dirección horizontal de viaje), la altitud o la velocidad del dispositivo. Esta información, y mucho más, está disponible en el objeto Location, que la app puede obtener del proveedor de ubicación combinada. En respuesta, la API actualiza la app de forma periódica con la mejor ubicación disponible, según los proveedores disponibles, como Wi-Fi y GPS (sistema de posicionamiento global). Se determina la precisión de la ubicación según los proveedores, los permisos de ubicación solicitados y las opciones que defines en la solicitud de ubicación.

En esta lección, se muestra cómo solicitar actualizaciones periódicas de la ubicación de un dispositivo usando el método requestLocationUpdates() en el proveedor de ubicación combinada.

Cómo conocer la ubicación más reciente

La ubicación conocida más reciente del dispositivo proporciona una base práctica de inicio y garantiza que la app tenga una ubicación conocida antes de comenzar las actualizaciones de ubicación periódicas. En la lección sobre Cómo obtener la última ubicación conocida, se muestra el instructivo para hacerlo llamando a getLastLocation(). En los fragmentos de las secciones siguientes, se asume que la app ya recuperó la última ubicación conocida y la almacenó como un objeto Location en la variable global mCurrentLocation.

Cómo realizar una solicitud de ubicación

Antes de solicitar actualizaciones de ubicación, la app debe conectarse a los servicios de ubicación y realizar una solicitud de ubicación. En la lección sobre Cómo cambiar la configuración de la ubicación, se incluyen las instrucciones. Una vez que se envía una solicitud de ubicación, puedes iniciar las actualizaciones periódicas llamando a requestLocationUpdates().

Según el formato de la solicitud, el proveedor de ubicación combinada invoca el método de devolución de llamada LocationCallback.onLocationResult() y le pasa una lista de objetos Location, o bien envía un PendingIntent que contiene la ubicación en los datos extendidos. La precisión y la frecuencia de las actualizaciones se ven afectadas por los permisos de ubicación solicitados y por las opciones que defines en el objeto de solicitud de ubicación.

En esta lección, se muestra cómo obtener la actualización con el método de devolución de llamada LocationCallback. Llama a requestLocationUpdates() y pásale la instancia del objeto LocationRequest y una LocationCallback. Define un método startLocationUpdates(), según se muestra en el siguiente ejemplo de código:

Kotlin

override fun onResume() {
    super.onResume()
    if (requestingLocationUpdates) startLocationUpdates()
}

private fun startLocationUpdates() {
    fusedLocationClient.requestLocationUpdates(locationRequest,
            locationCallback,
            Looper.getMainLooper())
}

Java

@Override
protected void onResume() {
    super.onResume();
    if (requestingLocationUpdates) {
        startLocationUpdates();
    }
}

private void startLocationUpdates() {
    fusedLocationClient.requestLocationUpdates(locationRequest,
            locationCallback,
            Looper.getMainLooper());
}

Ten en cuenta que el fragmento de código anterior hace referencia a una marca booleana, requestingLocationUpdates, que se usa para realizar un seguimiento de si el usuario activó o desactivó las actualizaciones de ubicación. Si el usuario desactivó las actualizaciones de ubicación, puedes informarlo sobre el requisito de ubicación de la app. Si quieres obtener más información para conservar el valor de la marca booleana en diferentes instancias de la actividad, consulta Cómo guardar el estado de la actividad.

Cómo definir la devolución de llamada de las actualizaciones de ubicación

El proveedor de ubicación combinada invoca el método de devolución de llamada LocationCallback.onLocationResult(). El argumento entrante tiene un objeto Location de lista que contiene la latitud y la longitud de la ubicación. En el siguiente fragmento, se muestra cómo implementar la interfaz LocationCallback y definir el método, además de obtener la marca de tiempo de la actualización de ubicación y mostrar la latitud, la longitud y la marca de tiempo en la interfaz de usuario de la app:

Kotlin

private lateinit var locationCallback: LocationCallback

// ...

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            for (location in locationResult.locations){
                // Update UI with location data
                // ...
            }
        }
    }
}

Java

private LocationCallback locationCallback;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...

    locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            for (Location location : locationResult.getLocations()) {
                // Update UI with location data
                // ...
            }
        }
    };
}

Cómo detener las actualizaciones de ubicación

Considera si deseas detener las actualizaciones de ubicación cuando la actividad ya no está enfocada, como cuando el usuario cambia a otra app o a una actividad diferente en la misma app. Esto puede servir para reducir el consumo de energía, siempre que la app no necesite recopilar información, incluso cuando se ejecuta en segundo plano. En esta sección, se muestra cómo detener las actualizaciones en el método onPause() de la actividad.

Para detener las actualizaciones de ubicación, llama a removeLocationUpdates() y pásale una LocationCallback, como se muestra en el siguiente ejemplo de código:

Kotlin

override fun onPause() {
    super.onPause()
    stopLocationUpdates()
}

private fun stopLocationUpdates() {
    fusedLocationClient.removeLocationUpdates(locationCallback)
}

Java

@Override
protected void onPause() {
    super.onPause();
    stopLocationUpdates();
}

private void stopLocationUpdates() {
    fusedLocationClient.removeLocationUpdates(locationCallback);
}

Usa un valor booleano, requestingLocationUpdates, para realizar un seguimiento de si las actualizaciones de ubicación están activadas en ese momento. En el método onResume() de la actividad, verifica si las actualizaciones de ubicación están activadas y, si no lo están, actívalas:

Kotlin

override fun onResume() {
    super.onResume()
    if (requestingLocationUpdates) startLocationUpdates()
}

Java

@Override
protected void onResume() {
    super.onResume();
    if (requestingLocationUpdates) {
        startLocationUpdates();
    }
}

Cómo guardar el estado de la actividad

Un cambio en la configuración del dispositivo, por ejemplo, en la orientación de la pantalla, puede destruir la actividad actual. Por lo tanto, tu app debe almacenar toda la información necesaria para recrear la actividad. Una forma de hacerlo es mediante un estado de instancia almacenado en un objeto Bundle.

En el siguiente ejemplo de código, se muestra cómo usar la devolución de llamada onSaveInstanceState() de la actividad para guardar el estado de la instancia:

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    outState?.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates)
    super.onSaveInstanceState(outState)
}

Java

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY,
            requestingLocationUpdates);
    // ...
    super.onSaveInstanceState(outState);
}

Define un método updateValuesFromBundle() para restablecer los valores guardados de la instancia anterior de la actividad si están disponibles. Llama al método desde el método onCreate() de la actividad, como se ve en la siguiente muestra de código:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    updateValuesFromBundle(savedInstanceState)
}

private fun updateValuesFromBundle(savedInstanceState: Bundle?) {
    savedInstanceState ?: return

    // Update the value of requestingLocationUpdates from the Bundle.
    if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
        requestingLocationUpdates = savedInstanceState.getBoolean(
                REQUESTING_LOCATION_UPDATES_KEY)
    }

    // ...

    // Update UI to match restored state
    updateUI()
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    updateValuesFromBundle(savedInstanceState);
}

private void updateValuesFromBundle(Bundle savedInstanceState) {
    if (savedInstanceState == null) {
        return;
    }

    // Update the value of requestingLocationUpdates from the Bundle.
    if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
        requestingLocationUpdates = savedInstanceState.getBoolean(
                REQUESTING_LOCATION_UPDATES_KEY);
    }

    // ...

    // Update UI to match restored state
    updateUI();
}

Si quieres obtener más información para guardar un estado de instancia, consulta la referencia de clase de actividad de Android.

Nota: Para obtener un almacenamiento más persistente, puedes guardar las preferencias del usuario en SharedPreferences de tu app. Establece la preferencia compartida en el método onPause() de la actividad y recupera la preferencia en onResume(). Si quieres obtener más información para guardar las preferencias, consulta Cómo guardar conjuntos de claves y valores.

Recursos adicionales

Para obtener más información, utiliza los siguientes recursos:

Ejemplos

  • App de ejemplo para demostrar la recepción de actualizaciones de ubicación en Android.