Sensor Event Handling in Android
Sensoren lifecycle-bewusst einsetzen und die richtige Abtastrate wählen. Spare Akku und erhalte zuverlässige Messdaten in deiner Android-App.
Sensoren gehören zu den vielseitigsten Bausteinen moderner Android-Apps. Ob Schrittzähler, Kompass oder Lagesensor – wer Rohdaten korrekt abonniert, die passende Abtastrate wählt und den Listener rechtzeitig wieder abmeldet, liefert präzise Ergebnisse, ohne den Akku des Nutzers zu ruinieren.
Was ist das?
Sensor Event Handling bezeichnet den gesamten Prozess, Messwerte von Gerätesensoren in einer Android-App zu empfangen und zu verarbeiten. Das Android-System stellt dafür den SensorManager-Dienst bereit, der als Vermittler zwischen physischer Hardware – Beschleunigungsmesser, Gyroskop, Magnetometer, Barometer, Näherungssensor und viele mehr – und deinem App-Code fungiert.
Ein einzelner Sensor Event besteht aus drei Informationen: einem Zeitstempel in Nanosekunden, einem Genauigkeitswert und einem float-Array mit den eigentlichen Messwerten. Wie viele Werte das Array enthält, hängt vom Sensortyp ab – ein Beschleunigungsmesser liefert drei Achsen (x, y, z), ein Näherungssensor nur einen Skalar.
Im Kontext der Android-Roadmap steht dieses Thema in Phase 9 – „Platform APIs and Device Capabilities” – weil Sensor-Integration eine echte Querschnittsaufgabe ist: Sie berührt Lifecycle-Management, die empfohlene Data-Layer-Architektur und dein Performance-Budget gleichzeitig. Wer hier schluderig vorgeht, baut eine App, die im Hintergrund unnötig Strom frisst oder ungenaue Daten an die UI schickt.
Wie funktioniert es?
Der Einstiegspunkt ist SensorManager, den du über getSystemService(Context.SENSOR_SERVICE) erhältst. Anschließend wählst du einen konkreten Sensor per getDefaultSensor(Int) und meldest einen SensorEventListener an. Dieser Listener hat zwei Callbacks: onSensorChanged(SensorEvent) für neue Messwerte und onAccuracyChanged(Sensor, Int) für Kalibrierungsänderungen.
Abtastrate steuern
Android bietet vier vordefinierte Konstanten, die als Hinweis an das System dienen – eine Garantie sind sie nicht:
| Konstante | Typisches Intervall | Anwendungsfall |
|---|---|---|
SENSOR_DELAY_NORMAL | ~200 ms | Kompass, Orientierung |
SENSOR_DELAY_UI | ~60 ms | Scroll-Gesten |
SENSOR_DELAY_GAME | ~20 ms | Spielsteuerung |
SENSOR_DELAY_FASTEST | < 5 ms | ML-Inferenz, Signalverarbeitung |
Ab API 19 kannst du alternativ registerListener(listener, sensor, samplingPeriodUs, maxReportLatencyUs) nutzen, um Abtastrate und maximale Latenz in Mikrosekunden exakt zu spezifizieren. Das gibt dem System mehr Spielraum, Events zu bündeln und so Energie zu sparen.
Lifecycle-Ankopplung
Ein Sensor, der weiterläuft, während deine App im Hintergrund ist, leert den Akku still und heimlich. Die korrekte Stelle zum Registrieren ist onResume(), zum Abmelden onPause(). In einem ViewModel oder Repository verwendest du stattdessen einen DefaultLifecycleObserver, damit der Listener sauber an den Lebenszyklus des LifecycleOwner gebunden bleibt und du keine direkte Activity-Referenz weitergeben musst.
Genauigkeit überwachen
onAccuracyChanged liefert einen von vier Statuswerten: SENSOR_STATUS_ACCURACY_HIGH, SENSOR_STATUS_ACCURACY_MEDIUM, SENSOR_STATUS_ACCURACY_LOW und SENSOR_STATUS_UNRELIABLE. Gerade Magnetometer reagieren empfindlich auf metallische Umgebungen und können kurzfristig auf UNRELIABLE fallen. Wenn du diesen Callback ignorierst, verarbeitest du möglicherweise Rohdaten, die keine realen Messwerte mehr darstellen.
In der Praxis
Das folgende Beispiel zeigt eine minimal lauffähige Kotlin-Activity, die den Beschleunigungsmesser lifecycle-korrekt einsetzt:
class SensorActivity : AppCompatActivity(), SensorEventListener {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onResume() {
super.onResume()
accelerometer?.let {
sensorManager.registerListener(
this,
it,
SensorManager.SENSOR_DELAY_NORMAL
)
}
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
override fun onSensorChanged(event: SensorEvent) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
// Rohdaten weiterverarbeiten oder in StateFlow schreiben
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
if (accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
// Nutzer auf Neukalibrierung hinweisen
}
}
}
Häufige Stolperfalle: Abmelden vergessen
Der mit Abstand häufigste Fehler ist, unregisterListener nur in onDestroy() statt in onPause() aufzurufen. Das lässt den Sensor im Hintergrund weiterlaufen – bei Fitness- oder AR-Apps kann das in 30 Minuten mehrere Prozent Akkukapazität kosten und fällt beim normalen Testen im Vordergrund oft überhaupt nicht auf. Prüfe im Android-Profiler unter „Energy Profiler”, ob der Sensor-Bedarf beim Wechsel in den Hintergrund sofort auf null fällt.
Integration in die Data Layer
Gemäß der offiziellen Android-Architektur gehört der Sensor-Zugriff in ein Repository, nicht direkt ins ViewModel oder in eine Composable-Funktion. Das Repository kapselt den SensorManager, wandelt Rohdaten in Domain-Objekte um und exponiert sie als Flow<SensorReading>. Das ViewModel abonniert diesen Flow, transformiert ihn bei Bedarf und leitet ihn als StateFlow an die UI weiter. So bleibt die Testbarkeit erhalten: Das Repository lässt sich durch eine Fake-Implementierung ersetzen, ohne dass echte Hardware nötig ist.
Fazit
Sensor Event Handling ist keine reine API-Übung – es ist ein Training in Ressourcendisziplin und sauberem Lifecycle-Management. Öffne dein nächstes Projekt und prüfe konkret: Ist jeder Sensor wirklich nur dann aktiv, wenn er gebraucht wird? Entspricht die gewählte Abtastrate dem tatsächlichen Bedarf, oder hast du aus Bequemlichkeit SENSOR_DELAY_FASTEST gesetzt? Schreib einen Instrumentierungstest, der überprüft, dass dein Repository nach onPause keine Werte mehr emittiert. Diese drei Checks zusammen machen den Unterschied zwischen einer App, die professionell mit Hardwareressourcen umgeht, und einer, die sich im Hintergrund durch den Akku frisst.