Componentes fundamentales en Android: Acelerómetro

- 👤 Andrés Cruz

🇺🇸 In english

Componentes fundamentales en Android: Acelerómetro

En esta entrada veremos unos de los componentes fundamentales que podemos encontrar en cualquier dispositivo Android relativamente reciente y se trata de un sensor que permite medir la aceleración del dispositivo: el acelerómetro.

El acelerómetro en Android se mide en base a los tres ejes conocidos (X,Y y Z); cada uno de ellos puede ser accedido a través de la clase SensorManager.

Método Moderno con Jetpack Compose

Con la llegada de Jetpack Compose, la forma de construir interfaces de usuario en Android ha cambiado significativamente. Aunque la lógica para acceder al sensor del acelerómetro es la misma (usando SensorManager), la forma en que gestionamos el estado y actualizamos la UI es diferente.

Ya no es necesario implementar SensorEventListener directamente en una Activity. En su lugar, podemos crear un composable que se encargue de registrar y escuchar los cambios del sensor.

La forma moderna de agregar librerías es usando un gestor de dependencias como Gradle. Las referencias a las librerías ya no se añaden manualmente, sino que se declaran en un fichero de configuración. Tu fichero build.gradle.kts (o build.gradle) del módulo de la app debería incluir las dependencias de Compose:


dependencies {
    def composeBom = platform("androidx.compose:compose-bom:2024.01.00")
    implementation composeBom
    androidTestImplementation composeBom

    implementation "androidx.activity:activity-compose:1.8.2"
    implementation "androidx.compose.material3:material3"
    implementation "androidx.compose.ui:ui"
    implementation "androidx.compose.ui:ui-tooling-preview"
    debugImplementation "androidx.compose.ui:ui-tooling"
}

A continuación, un ejemplo de cómo leer los datos del acelerómetro en un Composable:


import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext

@Composable
fun AccelerometerData(): Triple <Float, Float, Float> {
    val context = LocalContext.current
    var sensorData by remember { mutableStateOf(Triple(0f, 0f, 0f)) }

    DisposableEffect(Unit) {
        val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
        val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

        val sensorEventListener = object : SensorEventListener {
            override fun onSensorChanged(event: SensorEvent?) {
                if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) {
                    sensorData = Triple(event.values[0], event.values[1], event.values[2])
                }
            }

            override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
                // No es necesario para este ejemplo
            }
        }

        sensorManager.registerListener(
            sensorEventListener,
            accelerometer,
            SensorManager.SENSOR_DELAY_NORMAL
        )

        onDispose {
            sensorManager.unregisterListener(sensorEventListener)
        }
    }

    return sensorData
}

// En tu UI puedes usarlo así:
@Composable
fun MyScreen() {
    val (x, y, z) = AccelerometerData()
    Text(text = "X: $x, Y: $y, Z: $z")
}

En este ejemplo:

  • Usamos LocalContext.current para obtener el contexto actual dentro de un Composable.
  • remember y mutableStateOf se usan para guardar el estado de los valores del sensor. Cuando este estado cambia, Compose automáticamente redibuja la UI.
  • DisposableEffect es un efecto lateral de Compose que nos permite registrar el SensorEventListener cuando el composable entra en la composición y desregistrarlo cuando sale, evitando fugas de memoria.

Este enfoque es más declarativo y se integra mejor con el ciclo de vida de los componentes de Compose, representando la forma moderna de trabajar con sensores en Android.

Empezando con la clase de SensorManager en Android (Método Legacy)

Debemos de implementar la clase de SensorEventListener en nuestra actividad:

public class MainActivity extends Activity implements SensorEventListener

Una vez que implementamos la interfaz anterior debemos de sobrecargar los métodos:

@Override public void onSensorChanged(SensorEvent event) { } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { }

Solicitando acceso al acelerómetro

Lo siguiente que debemos hacer es solicitar acceso al acelerómetro del dispositivo; y esto lo hacemos a través del objeto SensorManager de la siguiente manera:

SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

Obtenemos el servicio del sistema a través del objeto getSystemService pasando como parámetro el nombre del servicio al que queremos acceder.

Obteniendo el acelerómetro del sistema

De la lista de sensores de vuelta en la consulta anterior, verificamos si hay algun sensor de tipo acelerómetro disponible; para ello se emplea la siguiente línea de código:

sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).size()

Registrando el evento "Escuchador" o Listener del acelerómetro

Una vez que hayamos verificado que el dispositivo cuenta con al menos un sensor de tipo acelerómetro podemos registrar el evento listener o escuchador:

sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST)

Pasamos como parámetro una instancia de la actividad, el acelerómetro y la tasa de refrescamiento, la cual puede ser:

  • SENSOR_DELAY_FASTEST
  • SENSOR_DELAY_NORMAL
  • SENSOR_DELAY_GAME
  • SENSOR_DELAY_UI

Lo único que varía entre ellas es la tasa de refrescamiento del acelerómetro.

Registrando el evento "Escuchador" o Listener

El método onSensorChanged se activa cada vez que el sistema detecta un cambio en la aceleración del dispositivo:

@Override public void onSensorChanged(SensorEvent event) { sensor = ""; sensor = "x: " + event.values[0] + " y: " + event.values[1] + " z: " + event.values[2]; }

Con el parámetro SensorEvent podemos tener entre varios datos, las coordenadas que el sistema usa en las rotaciones a través de los ejes X,Y y Z como vimos en el código anterior.

Puedes encontrar una aplicación funcional que ejemplifica el funcionamiento de los códigos vistos anteriormente en nuestro repositorio de GIT:

Descargar fuente

Captura de pantalla de la aplicación:

Acelerómetro en AnDroid

Acepto recibir anuncios de interes sobre este Blog.

En esta entrada veremos unos de los componentes fundamentales en todo dispositivo Android y se trata de un sensor que permite medir la aceleración del dispositivo: el acelerómetro.

| 👤 Andrés Cruz

🇺🇸 In english