Schlaffunktionen mit Health Connect entwickeln

Wenn Sie eine Funktion zur Schlaferfassung in Ihre App einbauen möchten, können Sie mit Health Connect Folgendes tun:

  • Schlafeinheiten schreiben
  • Daten zu Schlafphasen schreiben
  • Schlafdaten wie Herzfrequenz, Sauerstoffsättigung und Atemfrequenz schreiben
  • Schlafdaten aus anderen Apps lesen

In dieser Anleitung wird beschrieben, wie Sie diese Schlaffunktionen erstellen. Dabei werden Datentypen, Hintergrundausführung, Berechtigungen, empfohlene Workflows und Best Practices behandelt.

Übersicht: Umfassende Schlaferfassung erstellen

Mit Health Connect können Sie eine umfassende Schlaferfassung erstellen. Dazu sind folgende Schritte erforderlich:

  • Berechtigungen basierend auf Health-Berechtigungen korrekt implementieren.
  • Sitzungen mit SleepSessionRecord aufzeichnen.
  • Datentypen wie Schlafphasen, Herzfrequenz und Sauerstoffsättigung während der Sitzung einheitlich schreiben.
  • Hintergrundausführung richtig verwalten, um die kontinuierliche Datenerfassung über Nacht zu überprüfen.
  • Sitzungsdaten für Zusammenfassungen und Analysen nach dem Schlaf lesen.

Dieser Workflow ermöglicht die Interoperabilität mit anderen Health Connect-Apps und überprüft den nutzergesteuerten Datenzugriff.

Hinweis

Bevor Sie Schlaffunktionen implementieren:

Schlüsselkonzepte

Health Connect stellt Schlafdaten mit einigen Kernkomponenten dar. SleepSessionRecord dient als zentraler Eintrag für den Schlaf und enthält Details wie Start- und Endzeiten sowie Schlafphasen. Während einer Sitzung können verschiedene Datentypen wie HeartRateRecord oder OxygenSaturationRecord aufgezeichnet werden.

Schlafeinheiten

Schlafdaten werden durch SleepSessionRecord dargestellt. Jeder Eintrag speichert Folgendes:

  • startTime
  • endTime
  • stages: Eine Liste von SleepSessionRecord.Stage, einschließlich Tiefschlaf, leichter Schlaf, REM-Schlaf und Wachphasen.
  • Optionale Sitzungsmetadaten (Titel, Notizen)

Apps können mehrere Datentypen schreiben, die mit einer Sitzung verknüpft sind.

Datentypen

Zu den gängigen Datentypen, die während einer Schlafeinheit aufgezeichnet werden, gehören:

Jeder Datentyp wird als einzelner Eintrag gespeichert.

Überlegungen zur Entwicklung

Apps zur Schlaferfassung müssen oft über längere Zeiträume ausgeführt werden, häufig im Hintergrund, wenn der Bildschirm ausgeschaltet ist. Wenn Sie Ihre Schlaffunktionen erstellen, ist es wichtig, zu überlegen, wie Sie die Hintergrundausführung verwalten und die erforderlichen Berechtigungen für Schlafdaten anfordern.

Ausführung im Hintergrund

Apps zur Schlaferfassung werden in der Regel über Nacht ausgeführt, wenn der Bildschirm ausgeschaltet ist. In diesem Fall sollten Sie Folgendes verwenden:

  • Dienste im Vordergrund für die Datenerfassung
  • WorkManager für verzögertes Schreiben oder Synchronisieren
  • Batching-Strategien für regelmäßige Schreibvorgänge von detaillierten Daten wie der Herzfrequenz

Sorgen Sie für Kontinuität, indem Sie die Sitzungs-ID bei allen Schreibvorgängen einheitlich verwenden.

Berechtigungen

Ihre App muss die entsprechenden Health Connect-Berechtigungen anfordern, bevor sie Schlafdaten lesen oder schreiben kann. Eine vollständige Liste der Datentypen finden Sie unter Health Connect-Datentypen. Zu den gängigen Berechtigungen für den Schlaf gehören Schlafeinheiten und Messwerte wie Herzfrequenz oder Sauerstoffsättigung.

Der Zugriff auf Schlafdaten wird durch die folgenden Berechtigungen geschützt:

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

Wenn Sie Ihrer App Schlaffunktionen hinzufügen möchten, fordern Sie zuerst Berechtigungen für den Datentyp SleepSession an.

Hier ist die Berechtigung, die Sie deklarieren müssen, um Schlafdaten schreiben zu können:

<application>
  <uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>

Wenn Sie Schlafdaten lesen möchten, müssen Sie die folgenden Berechtigungen anfordern:

<application>
  <uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>

Im Folgenden sehen Sie ein Beispiel dafür, wie Sie Berechtigungen für eine Schlafeinheit anfordern, die Daten zur Herzfrequenz, Sauerstoffsättigung und Atemfrequenz enthält:

Nachdem Sie eine Client-Instanz erstellt haben, muss Ihre App Berechtigungen vom Nutzer anfordern. Nutzer müssen jederzeit Berechtigungen erteilen oder verweigern können.

Erstellen Sie dazu eine Reihe von Berechtigungen für die erforderlichen Datentypen. Achten Sie darauf, dass die Berechtigungen im Set zuerst in Ihrem Android-Manifest deklariert werden.

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(SleepSessionRecord::class),
  HealthPermission.getWritePermission(SleepSessionRecord::class),
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(OxygenSaturationRecord::class),
  HealthPermission.getWritePermission(OxygenSaturationRecord::class),
  HealthPermission.getReadPermission(RespiratoryRateRecord::class),
  HealthPermission.getWritePermission(RespiratoryRateRecord::class)
)

Mit getGrantedPermissions können Sie prüfen, ob Ihrer App bereits die erforderlichen Berechtigungen gewährt wurden. Falls nicht, fordern Sie diese Berechtigungen mit createRequestPermissionResultContract an. Daraufhin wird der Bildschirm mit den Health Connect-Berechtigungen angezeigt.

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

Da Nutzer Berechtigungen jederzeit erteilen oder widerrufen können, muss Ihre App jedes Mal vor der Verwendung von Berechtigungen prüfen, ob sie vorhanden sind, und Szenarien berücksichtigen, in denen Berechtigungen verloren gehen.

Schlafeinheit implementieren

In diesem Abschnitt wird der empfohlene Workflow zum Aufzeichnen von Schlafdaten beschrieben.

Um Datentypen wie HeartRateRecord oder OxygenSaturationRecord mit einer Schlafeinheit abzugleichen, zeichnen Sie sie mit Zeitstempeln auf, die zwischen startTime und endTime der Sitzung liegen. Health Connect verwendet keine Sitzungs-ID, um Schlafeinheiten mit detaillierten Daten zu verknüpfen. Stattdessen erfolgt die Zuordnung implizit durch überlappende Zeitintervalle. Wenn Sie Schlafdaten lesen, können Sie den Zeitraum einer Sitzung verwenden, um nach verknüpften Datentypen zu suchen. Weitere Informationen finden Sie unter Schlafdaten lesen.

Sitzung schreiben

Während einer Schlafeinheit können detaillierte Daten wie die Herzfrequenz aufgezeichnet werden. Der SleepSessionRecord selbst darf jedoch erst in Health Connect geschrieben werden, wenn die Sitzung beendet ist, z. B. wenn der Nutzer aufwacht. Der Eintrag muss die Sitzung startTime, endTime und eine Liste der während der Sitzung aufgezeichneten SleepSessionRecord.Stage Objekte enthalten, da für SleepSessionRecord gilt, dass endTime nach startTime liegen muss.

So schreiben Sie eine Schlafeinheit:

  1. Generieren Sie eine eindeutige Client-Eintrags-ID.
  2. Wenn der Nutzer aufwacht oder die Schlaferfassung beendet wird, erfassen Sie alle Schlafphasen und erstellen Sie einen SleepSessionRecord.
  3. Fügen Sie den Eintrag mit insertRecords ein.

Beispiel:

val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)

val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(3600),
    endTime = sessionStartTime.plusSeconds(7200),
    stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(7200),
    endTime = sessionStartTime.plusSeconds(10800),
    stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages

val session = SleepSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    stages = stages,
    metadata = Metadata(clientRecordId = clientRecordId)
)

healthConnectClient.insertRecords(listOf(session))

Schlafdaten lesen

Apps können Schlafeinheiten und die zugehörigen Daten lesen, um Aktivitäten zusammenzufassen, Gesundheitsinformationen zu liefern oder Daten mit einem externen Server zu synchronisieren. Sie können beispielsweise einen SleepSessionRecord lesen und dann die HeartRateRecord abfragen, die im selben Zeitraum aufgezeichnet wurde.

Sitzung mit zugehörigen Daten lesen

Sie können Schlafeinheiten mit einer ReadRecordsRequest lesen, wobei SleepSessionRecord als Eintragstyp verwendet wird und nach einem Zeitraum gefiltert wird. Wenn Sie zugehörige Daten für eine bestimmte Sitzung lesen möchten, stellen Sie eine zweite Anfrage für den ausgewählten Datentyp, z. B. HeartRateRecord, und filtern Sie nach startTime und endTime der Schlafeinheit.

Im folgenden Beispiel wird gezeigt, wie Sie Schlafeinheiten mit zugehörigen Herzfrequenzdaten für einen bestimmten Zeitraum lesen:

suspend fun readSleepSessionsWithAssociatedData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (sleepRecord in response.records) {
        // Process each session
        val stages = sleepRecord.stages
        val notes = sleepRecord.notes

        // To read specific granular data (like heart rate) that occurred during
        // this session, use the session's startTime and endTime to filter
        // the request for that data type.
        val hrResponse = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(
                    sleepRecord.startTime,
                    sleepRecord.endTime
                )
            )
        )
        for (heartRateRecord in hrResponse.records) {
            for (sample in heartRateRecord.samples) {
                val bpm = sample.beatsPerMinute
            }
        }
    }
}

Best Practices

Beachten Sie diese Richtlinien, um die Zuverlässigkeit der Daten und die Nutzerfreundlichkeit zu verbessern:

  • Schreibhäufigkeit
    • Aktive Erfassung(Vordergrund) : Schreiben Sie bei der aktiven Schlaferfassung Daten, sobald sie verfügbar sind, oder in einem maximalen Intervall von 15 Minuten.
    • Hintergrundsynchronisierung:Verwenden Sie WorkManager für verzögerte Schreibvorgänge. Ein Intervall von 15 Minuten ist ein guter Kompromiss zwischen Echtzeitdaten und Akkueffizienz.
    • Batching:Schreiben Sie nicht jedes einzelne Sensorereignis einzeln. Chunk-Anfragen verwenden. Health Connect verarbeitet bis zu 1.000 Einträge pro Schreibanfrage.
  • Sitzungs-IDs stabil und eindeutig halten:Verwenden Sie einheitliche IDs für Ihre Sitzungen. Wenn eine Sitzung bearbeitet oder aktualisiert wird, wird sie durch die Verwendung derselben ID nicht als neue, separate Schlafeinheit behandelt.
  • Batching für Datentypen verwenden:Um den Input/Output-Overhead zu reduzieren und die Akkulaufzeit zu verlängern, gruppieren Sie Ihre Datenpunkte in einem einzigen insertRecords-Aufruf, anstatt jeden Punkt einzeln zu schreiben.
  • Doppelte Daten vermeiden: Client-IDs verwenden Wenn Sie Einträge erstellen, legen Sie eine metadata.clientRecordId fest. Health Connect verwendet diese ID, um eindeutige Einträge zu identifizieren. Wenn Sie versuchen, einen Eintrag mit einer bereits vorhandenen clientRecordId zu schreiben, ignoriert Health Connect das Duplikat oder aktualisiert den vorhandenen Eintrag, anstatt einen neuen zu erstellen. Das Festlegen einer metadata.clientRecordId ist die effektivste Methode, um Duplikate bei Synchronisierungsversuchen oder Neuinstallationen von Apps zu vermeiden.

    val record = RespiratoryRateRecord(
        rate = 16.0,
        time = time,
        zoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "respiratory_rate_20231030_1"
        )
    )
    
  • Vorhandene Daten prüfen:Fragen Sie vor der Synchronisierung den Zeitraum ab, um zu prüfen, ob bereits Einträge aus Ihrer App vorhanden sind.

  • Zeitstempel dürfen sich nicht überschneiden:Prüfen Sie, ob eine neue Sitzung erst beginnt, nachdem die vorherige beendet wurde. Überlappende Sitzungen können zu Konflikten in Fitness-Dashboards und bei Zusammenfassungsberechnungen führen.

  • Berechtigungen klar begründen:Verwenden Sie den Permission.createIntent-Ablauf, um zu erklären, warum Ihre App Zugriff auf Gesundheitsdaten benötigt, z. B. „Um Ihre Schlafmuster zu analysieren“.

  • Lange Sitzungen testen:Überwachen Sie den Akkuverbrauch bei Sitzungen, die mehrere Stunden dauern, um zu prüfen, ob das Batching-Intervall und die Sensornutzung den Akku nicht zu stark belasten.

  • Zeitstempel an Sensorraten anpassen:Passen Sie die Zeitstempel Ihrer Einträge an die tatsächliche Frequenz Ihrer Sensoren an, um eine hohe Datentreue zu gewährleisten.

Testen

Um die Richtigkeit der Daten und eine hohe Nutzerfreundlichkeit zu gewährleisten, folgen Sie diesen Teststrategien und lesen Sie die offizielle Dokumentation zu den wichtigsten Anwendungsfällen für Tests.

Tools zur Überprüfung

  • **Health Connect Toolbox**: Mit dieser Begleit-App können Sie Einträge manuell prüfen, Testdaten löschen und Änderungen an der Datenbank simulieren. So lässt sich am besten prüfen, ob Ihre Einträge korrekt gespeichert werden.
  • Unit-Tests mit FakeHealthConnectClient: Mit der Testbibliothek können Sie prüfen, wie Ihre App Grenzfälle wie den Widerruf von Berechtigungen oder API Ausnahmen behandelt, ohne dass ein physisches Gerät erforderlich ist.

Checkliste für Qualität

Typische Architektur

Eine Implementierung zur Schlaferfassung umfasst in der Regel Folgendes:

Komponente Verwaltet
Sitzungscontroller Sitzungsstatus
Timer
Batching-Logik
Controller für Datentypen
Datenerfassung
Repository-Ebene (fasst Health Connect-Vorgänge zusammen): Sitzung einfügen
Datentypen einfügen
Schlafphasen einfügen
Sitzungszusammenfassungen lesen
UI-Ebene (zeigt Folgendes an): Dauer
Live-Datentypen
Visualisierung der Schlafphasen

Fehlerbehebung

Symptom Mögliche Ursache Lösung
Fehlende Datentypen (z. B. Herzfrequenz) Fehlende Schreibberechtigungen oder falsche Zeitfilter. Prüfen Sie, ob Sie die Berechtigung für den jeweiligen Datentyp angefordert haben und ob der Nutzer sie erteilt hat. Prüfen Sie, ob Ihre ReadRecordsRequest einen TimeRangeFilter verwendet, der mit der Sitzung übereinstimmt. Weitere Informationen finden Sie unter Berechtigungen.
Sitzung kann nicht geschrieben werden Überlappende Zeitstempel. Health Connect lehnt möglicherweise Einträge ab, die sich mit vorhandenen Daten aus derselben App überschneiden. Prüfen Sie, ob die startTime einer neuen Sitzung nach der endTime der vorherigen Sitzung liegt.
Während des Schlafs werden keine Sensordaten aufgezeichnet Der Dienst im Vordergrund wurde beendet oder ist inaktiv. Wenn Sie über Nacht Sensordaten erfassen möchten, während der Bildschirm ausgeschaltet ist, können Sie einen Dienst im Vordergrund mit foregroundServiceType="health" verwenden.
Doppelte Einträge werden angezeigt clientRecordId fehlt. Weisen Sie in den Metadata jedes Eintrags eine eindeutige clientRecordId zu. So kann Health Connect Duplikate entfernen, wenn dieselben Daten bei einem Synchronisierungsversuch zweimal geschrieben werden. Weitere Informationen finden Sie unter Best Practices.

Allgemeine Schritte zur Fehlerbehebung

Berechtigungsstatus prüfen. Rufen Sie immer getPermissionStatus() auf, bevor Sie einen Lese- oder Schreibvorgang ausführen. Nutzer können Berechtigungen jederzeit in den Systemeinstellungen widerrufen.
Ausführungsmodus prüfen. Wenn Ihre App keine Daten im Hintergrund erfasst, prüfen Sie, ob Sie die richtigen Berechtigungen in Ihrer AndroidManifest.xml-Datei deklariert haben und ob der Nutzer die App nicht in den Modus „Akkunutzung eingeschränkt“ versetzt hat.