Sviluppare esperienze di sonno con Connessione Salute

Se vuoi creare un'esperienza di monitoraggio del sonno nella tua app, puoi utilizzare Health Connect per svolgere attività come:

  • Scrivere sessioni di sonno
  • Scrivere dati sulle fasi del sonno
  • Scrivere dati relativi al sonno, ad esempio frequenza cardiaca, saturazione di ossigeno e frequenza respiratoria
  • Leggere i dati relativi al sonno da altre app

Questa guida descrive come creare queste funzionalità relative al sonno, trattando tipi di dati, esecuzione in background, autorizzazioni, flussi di lavoro consigliati e best practice.

Panoramica: creare un monitoraggio del sonno completo

Puoi creare un'esperienza di monitoraggio del sonno completa utilizzando Health Connect seguendo questi passaggi principali:

  • Implementare correttamente le autorizzazioni in base alle autorizzazioni relative alla salute.
  • Registrare le sessioni utilizzando SleepSessionRecord.
  • Scrivere in modo coerente tipi di dati come fasi del sonno, frequenza cardiaca e saturazione di ossigeno durante la sessione.
  • Gestire correttamente l'esecuzione in background per verificare l'acquisizione continua dei dati durante la notte.
  • Leggere i dati della sessione per riepiloghi e analisi post-sonno.

Questo workflow consente l'interoperabilità con altre app di Health Connect e verifica l'accesso ai dati controllato dall'utente.

Prima di iniziare

Prima di implementare le funzionalità relative al sonno:

Concetti principali

Health Connect rappresenta i dati relativi al sonno utilizzando alcuni componenti principali. Un SleepSessionRecord funge da record centrale per il sonno e contiene dettagli come orari di inizio o fine e fasi del sonno. Durante una sessione, è possibile registrare vari tipi di dati, ad esempio HeartRateRecord o OxygenSaturationRecord.

Sessioni di sonno

I dati relativi al sonno sono rappresentati da SleepSessionRecord. Ogni record memorizza:

  • startTime
  • endTime
  • stages: un elenco di SleepSessionRecord.Stage che include sonno profondo, leggero, REM e di veglia.
  • Metadati della sessione facoltativi (titolo, note)

Le app possono scrivere più tipi di dati associati a una sessione.

Tipi di dati

I tipi di dati comuni registrati durante una sessione di sonno includono:

Ogni tipo di dati viene archiviato come record individuale.

Considerazioni sullo sviluppo

Le app di monitoraggio del sonno spesso devono essere eseguite per periodi prolungati, di frequente in background quando lo schermo è spento. Quando crei le funzionalità relative al sonno, è importante considerare come gestire l'esecuzione in background e richiedere le autorizzazioni necessarie per i dati sul sonno.

Esecuzione in background

Le app di monitoraggio del sonno in genere vengono eseguite durante la notte con lo schermo spento. In questo stato, devi utilizzare:

  • Servizi in primo piano per la raccolta dei dati
  • WorkManager per la scrittura o la sincronizzazione differita
  • Strategie di batch per le scritture di record regolari di dati granulari come la frequenza cardiaca

Mantieni la continuità mantenendo coerente l'ID sessione in tutte le scritture.

Autorizzazioni

La tua app deve richiedere le autorizzazioni di Health Connect pertinenti prima di leggere o scrivere i dati relativi al sonno. Per un elenco completo dei tipi di dati, vedi Tipi di dati di Health Connect. Le autorizzazioni comuni per il sonno includono sessioni di sonno e metriche come frequenza cardiaca o saturazione di ossigeno.

L'accesso al sonno è protetto dalle seguenti autorizzazioni:

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

Per aggiungere la funzionalità di sonno alla tua app, inizia richiedendo le autorizzazioni per il tipo di dati SleepSession.

Ecco l'autorizzazione che devi dichiarare per poter scrivere il sonno:

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

Per leggere il sonno, devi richiedere le seguenti autorizzazioni:

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

Di seguito è riportato un esempio di come richiedere le autorizzazioni per una sessione di sonno che include dati su frequenza cardiaca, saturazione di ossigeno e frequenza respiratoria:

Dopo aver creato un'istanza client, la tua app deve richiedere le autorizzazioni all'utente. Gli utenti devono poter concedere o negare le autorizzazioni in qualsiasi momento.

A questo scopo, crea un set di autorizzazioni per i tipi di dati richiesti. Assicurati che le autorizzazioni nel set siano dichiarate prima nel manifest di Android.

// 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)
)

Utilizza getGrantedPermissions per verificare se la tua app ha già le autorizzazioni richieste. In caso contrario, utilizza createRequestPermissionResultContract per richiedere queste autorizzazioni. Viene visualizzata la schermata delle autorizzazioni di Health Connect.

// 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)
  }
}

Poiché gli utenti possono concedere o revocare le autorizzazioni in qualsiasi momento, la tua app deve controllare le autorizzazioni ogni volta prima di utilizzarle e gestire gli scenari in cui l'autorizzazione viene revocata.

Implementare una sessione di sonno

Questa sezione descrive il flusso di lavoro consigliato per la registrazione dei dati relativi al sonno.

Per allineare i tipi di dati come HeartRateRecord o OxygenSaturationRecord a una sessione di sonno, registrali con timestamp che rientrano tra startTime e endTime della sessione. Health Connect non utilizza un identificatore di sessione per collegare le sessioni di sonno ai dati granulari. Al contrario, l'associazione è implicita tramite intervalli di tempo sovrapposti. Quando leggi i dati relativi al sonno, puoi utilizzare l'intervallo di tempo di una sessione per eseguire query sui tipi di dati associati, come mostrato in Lettura dei dati relativi al sonno.

Scrivere una sessione

Sebbene i dati granulari come la frequenza cardiaca possano essere registrati durante una sessione di sonno, SleepSessionRecord stesso deve essere scritto in Health Connect solo al termine della sessione, ad esempio quando l'utente si sveglia. Il record deve includere startTime, endTime della sessione e un elenco di SleepSessionRecord.Stage oggetti registrati durante la sessione, poiché SleepSessionRecord richiede che endTime sia successivo a startTime.

Per scrivere una sessione di sonno:

  1. Genera un ID record client univoco.
  2. Quando l'utente si sveglia o il monitoraggio del sonno viene interrotto, raccogli tutte le fasi del sonno e crea un SleepSessionRecord.
  3. Inserisci il record utilizzando insertRecords.

Esempio:

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))

Lettura dei dati relativi al sonno

Le app possono leggere le sessioni di sonno e i dati associati per riepilogare l'attività, fornire approfondimenti sulla salute o sincronizzare i dati con un server esterno. Ad esempio, puoi leggere un SleepSessionRecord e poi eseguire una query su HeartRateRecord che si è verificato nello stesso intervallo di tempo.

Leggere la sessione con i dati associati

Puoi leggere le sessioni di sonno utilizzando un ReadRecordsRequest con SleepSessionRecord come tipo di record, filtrato in base a un intervallo di tempo. Per leggere i dati associati per una determinata sessione, effettua una seconda richiesta per il tipo di dati selezionato, ad esempio HeartRateRecord, filtrando in base a startTime e endTime della sessione di sonno.

L'esempio seguente mostra come leggere le sessioni di sonno con i dati sul battito cardiaco associati per un determinato intervallo di tempo:

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 practice

Segui queste linee guida per migliorare l'affidabilità dei dati e l'esperienza utente:

  • Scrivi spesso durante il monitoraggio attivo: per il monitoraggio attivo, scrivi i dati non appena diventano disponibili o a un intervallo massimo di 15 minuti.
  • Utilizza WorkManager per le sincronizzazioni in background: utilizza WorkManager per le scritture differite. Punta a un intervallo di 15 minuti per trovare un equilibrio tra dati in tempo reale ed efficienza della batteria.
  • Richieste di scrittura batch: non scrivere ogni singolo evento del sensore singolarmente. Dividi le richieste in blocchi. Health Connect gestisce fino a 1000 record per richiesta di scrittura.
  • Mantieni gli ID sessione stabili e univoci: utilizza identificatori coerenti per le sessioni. Se una sessione viene modificata o aggiornata, l'utilizzo dello stesso ID impedisce che venga trattata come una nuova sessione separata.
  • Utilizza il batch per i tipi di dati: per ridurre il sovraccarico di input/output e preservare la durata della batteria, raggruppa i punti dati in una singola chiamata insertRecords anziché scrivere ogni punto singolarmente.
  • Evita di scrivere dati duplicati: utilizza gli ID client: quando crei i record, imposta un metadata.clientRecordId. Health Connect lo utilizza per identificare i record univoci. Se tenti di scrivere un record con un clientRecordId già esistente, Health Connect ignorerà il duplicato o aggiornerà il record esistente anziché crearne uno nuovo. L'impostazione di un metadata.clientRecordId è il modo più efficace per evitare duplicati durante i tentativi di sincronizzazione o le reinstallazioni dell'app.
    val record = StepsRecord(
        count = 100,
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "daily_steps_2023_10_27_user_123"
        )
    )
  • Controlla i dati esistenti: prima della sincronizzazione, esegui una query sull'intervallo di tempo per verificare se esistono già record della tua app.
  • Assicurati che i timestamp non si sovrappongano: verifica che una nuova sessione non inizi prima della fine della precedente. Le sessioni sovrapposte possono causare conflitti nei dashboard di fitness e nei calcoli di riepilogo.
  • Fornisci motivazioni chiare per l'autorizzazione: utilizza il flusso Permission.createIntent per spiegare perché la tua app ha bisogno di accedere ai dati sulla salute, ad esempio: "Per monitorare le tendenze della pressione sanguigna e fornire approfondimenti".
  • Testa le sessioni a lunga esecuzione: monitora il consumo della batteria durante le sessioni che durano diverse ore per verificare che l'intervallo di batch e l'utilizzo dei sensori non scarichino il dispositivo.
  • Allinea i timestamp alle frequenze dei sensori: abbina i timestamp dei record alla frequenza effettiva dei sensori per mantenere un'elevata fedeltà dei dati.

Test

Per verificare la correttezza dei dati e un'esperienza utente di alta qualità, segui queste strategie di test e consulta la documentazione ufficiale Test dei casi d'uso principali.

Strumenti di verifica

  • Health Connect Toolbox: utilizza questa app complementare per esaminare manualmente i record, eliminare i dati di test e simulare le modifiche al database. È il modo migliore per verificare che i record vengano archiviati correttamente.
  • Test delle unità con FakeHealthConnectClient: utilizza la libreria di test per verificare in che modo la tua app gestisce i casi limite, come la revoca delle autorizzazioni o le eccezioni API, senza la necessità di un dispositivo fisico.

Elenco di controllo della qualità

Architettura tipica

Un'implementazione del monitoraggio del sonno in genere include:

Componente Gestisce
Controller sessione Stato sessione
Timer
Logica di batch
Controller dei tipi di dati
Raccolta dei dati
Livello repository (esegue il wrapping delle operazioni di Health Connect): Inserisci sessione
Inserisci tipi di dati
Inserisci fasi del sonno
Leggi i riepiloghi delle sessioni
Livello UI (visualizza): Durata
Tipi di dati in tempo reale
Visualizzazione delle fasi del sonno

Risoluzione dei problemi

Sintomo Possibile causa Risoluzione
Tipi di dati mancanti (ad esempio, battito cardiaco) Autorizzazioni di scrittura mancanti o filtri temporali errati. Verifica di aver richiesto e che l'utente abbia concesso l'autorizzazione per il tipo di dati specifico. Verifica che ReadRecordsRequest utilizzi un TimeRangeFilter che corrisponda alla sessione. Vedi Autorizzazioni.
Impossibile scrivere la sessione Timestamp sovrapposti. Health Connect potrebbe rifiutare i record che si sovrappongono ai dati esistenti della stessa app. Verifica che startTime di una nuova sessione sia successivo a endTime della precedente.
Nessun dato dei sensori registrato durante il sonno Il servizio in primo piano è stato interrotto o è inattivo. Per raccogliere i dati dei sensori durante la notte mentre lo schermo è spento, puoi utilizzare un servizio in primo piano con foregroundServiceType="health".
Vengono visualizzati record duplicati clientRecordId mancante. Assegna un clientRecordId univoco in Metadata di ogni record. In questo modo, Health Connect può eseguire la deduplicazione se gli stessi dati vengono scritti due volte durante un tentativo di sincronizzazione. Vedi Best practice.

Passaggi comuni per il debug

Controlla lo stato delle autorizzazioni. Chiama sempre getPermissionStatus() prima di tentare un'operazione di lettura o scrittura. Gli utenti possono revocare le autorizzazioni nelle impostazioni di sistema in qualsiasi momento.
Verifica la modalità di esecuzione. Se la tua app non raccoglie dati in background, verifica di aver dichiarato le autorizzazioni corrette nel file AndroidManifest.xml e che l'utente non abbia impostato l'app in modalità "Batteria limitata".