Se vuoi creare un'esperienza di allenamento nella tua app, puoi utilizzare Connessione Salute per svolgere attività come:
- Scrivere le sessioni di allenamento
- Scrivere i percorsi di allenamento
- Scrivere le metriche di allenamento, come frequenza cardiaca, velocità e distanza
- Leggere i dati di allenamento da altre app
Questa guida descrive come creare queste funzionalità di attività fisica, trattando i tipi di dati, l'esecuzione in background, le autorizzazioni, i workflow consigliati e le best practice.
Panoramica: creare un tracker di allenamento completo
Puoi creare un'esperienza di monitoraggio dell'attività fisica completa utilizzando Health Connect seguendo questi passaggi principali:
- Implementare correttamente le autorizzazioni in base alle autorizzazioni relative alla salute.
- Registrare le sessioni utilizzando
ExerciseSessionRecord. - Scrivere i dati di allenamento in modo coerente durante la sessione.
- Gestire correttamente l'esecuzione in background per verificare l'acquisizione continua dei dati.
- Leggere i dati della sessione per riepiloghi e analisi post-allenamento.
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à di allenamento:
- Integra Health Connect utilizzando la dipendenza appropriata.
- Crea un'istanza di
HealthConnectClient. - Verifica che la tua app implementi i flussi di autorizzazioni di runtime in base alle autorizzazioni relative alla salute.
- Se il workflow utilizza il GPS, configura l'autorizzazione di accesso alla posizione e un servizio in primo piano.
Concetti principali
Health Connect rappresenta i dati di allenamento utilizzando alcuni componenti principali. Un ExerciseSessionRecord funge da record centrale per un allenamento e contiene dettagli come l'ora di inizio o di fine e il tipo di esercizio. Durante una sessione, è possibile registrare vari tipi di dati, come HeartRateRecord o SpeedRecord. Per le attività all'aperto, ExerciseRoute memorizza i dati GPS, collegati alla sessione corrispondente.
Sessioni di allenamento
ExerciseSessionRecord è il record centrale per i dati di allenamento e rappresenta una singola sessione di allenamento. Ogni record memorizza:
startTimeendTimeexerciseType- Metadati della sessione facoltativi (titolo, note)
Un ExerciseSessionRecord può anche contenere percorsi di allenamento, giri e segmenti come parte dei suoi dati. Inoltre, durante una sessione è possibile registrare e associare altri tipi di dati, come HeartRateRecord o SpeedRecord.
Tipi di dati associati
I dati associati alle sessioni di allenamento sono rappresentati da singoli tipi di record. I tipi comuni includono:
HeartRateRecord: rappresenta una serie di misurazioni della frequenza cardiaca.SpeedRecord: rappresenta una serie di misurazioni della velocità.DistanceRecord: rappresenta la distanza percorsa tra le letture.TotalCaloriesBurnedRecord: rappresenta le calorie totali bruciate tra le letture.ElevationGainedRecord: rappresenta l'altitudine raggiunta tra le letture.StepsCadenceRecord: rappresenta la frequenza del passo tra le letture.PowerRecord: rappresenta la potenza erogata tra le letture, comune in attività come il ciclismo.
Per un elenco completo dei tipi di dati, vedi Tipi di dati di Health Connect.
Percorsi di allenamento
Puoi associare un percorso agli allenamenti all'aperto utilizzando ExerciseRoute. I percorsi sono costituiti da oggetti ExerciseRoute.Location sequenziali, ognuno dei quali contiene:
- Latitudine e longitudine
- Altitudine facoltativa
- Rilevamento facoltativo
- Informazioni sull'accuratezza
- Timestamp
Collegare i percorsi delle sessioni
Un ExerciseRoute contiene i dati sulla posizione sequenziali per una sessione di allenamento. Non viene trattato come un record indipendente in Health Connect. Invece, fornisci i dati ExerciseRoute quando inserisci o aggiorni un ExerciseSessionRecord.
Considerazioni sullo sviluppo
Le app di monitoraggio dell'attività fisica spesso devono essere eseguite per periodi prolungati, di frequente in background quando lo schermo è spento. Quando crei le funzionalità per l'attività fisica, è importante considerare come gestire l'esecuzione in background e richiedere le autorizzazioni necessarie per i dati dell'attività fisica.
Esecuzione in background
Le app di allenamento vengono comunemente eseguite con lo schermo spento. In questo stato, devi utilizzare:
- Servizi in primo piano per il campionamento della posizione e dei sensori
WorkManagerper la scrittura o la sincronizzazione posticipata- Strategie di batch per la scrittura regolare dei record
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 di allenamento. Le autorizzazioni comuni per gli allenamenti includono sessioni di allenamento, percorsi di allenamento e metriche come frequenza cardiaca o velocità. È incluso quanto segue:
- Sessioni di allenamento: autorizzazioni di lettura e scrittura per
ExerciseSessionRecord. - Percorsi di allenamento: autorizzazioni di lettura e scrittura per
ExerciseRoute. - Frequenza cardiaca: autorizzazioni di lettura e scrittura per
HeartRateRecord. - Velocità: autorizzazioni di lettura e scrittura per
SpeedRecord. - Distanza: autorizzazioni di lettura e scrittura per
DistanceRecord. - Calorie: autorizzazioni di lettura e scrittura per
TotalCaloriesBurnedRecord. - Altitudine raggiunta: autorizzazioni di lettura e scrittura per
ElevationGainedRecord. - Frequenza del passo: autorizzazioni di lettura e scrittura per
StepsCadenceRecord. - Potenza: autorizzazioni di lettura e scrittura per
PowerRecord. - Passi: autorizzazioni di lettura e scrittura per
StepsRecord.
Di seguito è riportato un esempio di come richiedere più autorizzazioni per una sessione di attività fisica che include dati su percorso, frequenza cardiaca, distanza, calorie, velocità e passi:
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(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class),
HealthPermission.getReadPermission(ExerciseRoute::class),
HealthPermission.getWritePermission(ExerciseRoute::class),
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(SpeedRecord::class),
HealthPermission.getWritePermission(SpeedRecord::class),
HealthPermission.getReadPermission(DistanceRecord::class),
HealthPermission.getWritePermission(DistanceRecord::class),
HealthPermission.getReadPermission(TotalCaloriesBurnedRecord::class),
HealthPermission.getWritePermission(TotalCaloriesBurnedRecord::class),
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::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.
Per richiedere le autorizzazioni, chiama la funzione checkPermissionsAndRun:
if (!granted.containsAll(PERMISSIONS)) {
requestPermissions.launch(PERMISSIONS)
// Check if required permissions are not granted, and return
}
// Permissions already granted; proceed with inserting or reading data
Se devi richiedere le autorizzazioni solo per un singolo tipo di dati, ad esempio il battito cardiaco, includi solo quel tipo di dati nel set di autorizzazioni:
L'accesso alla frequenza cardiaca è protetto dalle seguenti autorizzazioni:
android.permission.health.READ_HEART_RATEandroid.permission.health.WRITE_HEART_RATE
Per aggiungere la funzionalità di frequenza cardiaca alla tua app, inizia richiedendo le autorizzazioni per il tipo di dati HeartRateRecord.
Ecco l'autorizzazione che devi dichiarare per poter scrivere la frequenza cardiaca:
<application>
<uses-permission
android:name="android.permission.health.WRITE_HEART_RATE" />
...
</application>
Per leggere la frequenza cardiaca, devi richiedere le seguenti autorizzazioni:
<application>
<uses-permission
android:name="android.permission.health.READ_HEART_RATE" />
...
</application>
Implementare una sessione di allenamento
Questa sezione descrive il flusso di lavoro consigliato per la registrazione dei dati di allenamento.
Avviare la sessione
Per creare un nuovo allenamento:
- Genera un ID sessione univoco: verifica che questo ID sia stabile. Se il processo dell'app viene interrotto e riavviato, devi essere in grado di riprendere l'utilizzo dello stesso ID per evitare sessioni frammentate.
- Imposta un
metadata.clientRecordIdper evitare duplicati durante i tentativi di sincronizzazione. - Scrivi un
ExerciseSessionRecord: includi l'ora di inizio. - Inizia a raccogliere i dati del tipo di dati e del GPS: inizia solo dopo che il record della sessione è stato inizializzato correttamente.
Esempio:
val sessionId = UUID.randomUUID().toString()
val sessionClientId = UUID.randomUUID().toString()
val session = ExerciseSessionRecord(
id = sessionId,
exerciseType = ExerciseType.EXERCISE_TYPE_RUNNING,
startTime = Instant.now(),
endTime = null,
metadata = Metadata(clientRecordId = sessionClientId),
)
healthConnectClient.insertRecords(listOf(session))
Registrare i percorsi di allenamento
Per saperne di più sulla lettura delle indicazioni, vedi Leggere i dati non elaborati.
Quando registri un percorso di allenamento, devi raggruppare i dati. Ciò significa che, anziché salvare ogni singolo punto GPS man mano che si verifica, raccogli un gruppo di punti e li salvi tutti in una sola chiamata.
Questo è importante perché ogni volta che la tua app legge o scrive in Health Connect, utilizza una piccola quantità di batteria e potenza di elaborazione.
Il seguente codice mostra come registrare in batch:
// 1. Create a list to hold your route locations
val routeLocations = mutableListOf<ExerciseRoute.Location>()
// 2. Add points to your list as the exercise happens
routeLocations.add(
ExerciseRoute.Location(
time = Instant.now(),
latitude = 37.7749,
longitude = -122.4194
)
)
// ... keep adding points over a period of time ...
// 3. Save the whole list at once (Batching)
val session = ExerciseSessionRecord(
startTime = startTime,
endTime = endTime,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
// We pass the whole list here
exerciseRoute = ExerciseRoute(routeLocations)
)
healthConnectClient.insertRecords(listOf(session))
Terminare una sessione
Dopo aver interrotto la raccolta dei dati:
- Aggiorna il record: la tua app aggiorna
ExerciseSessionRecordcon unendTime. - Finalizza i dati: facoltativamente, calcola i valori di riepilogo (come la distanza totale o la velocità media) e scrivili come record aggiuntivi.
val finishedSession = session.copy(endTime = Instant.now())
healthConnectClient.updateRecords(listOf(finishedSession))
Leggere i dati di allenamento
Le app possono leggere le sessioni di allenamento e i dati associati per riepilogare l'attività, fornire informazioni sulla salute o sincronizzare i dati con un server esterno. Ad esempio, puoi leggere un ExerciseSessionRecord e poi eseguire una query su HeartRateRecord o DistanceRecord che si sono verificati nello stesso intervallo di tempo.
Se devi sincronizzare i dati di allenamento con un server di backend o mantenere aggiornato il datastore della tua app con Health Connect, utilizza ChangeLogs. In questo modo, puoi recuperare un elenco di record inseriti, aggiornati o eliminati da un punto specifico nel tempo, il che è più efficiente rispetto al monitoraggio manuale delle modifiche o alla lettura ripetuta di tutti i dati. Per saperne di più, vedi Sincronizzare i dati con Health Connect.
Leggere le sessioni
Per leggere le sessioni di allenamento, utilizza un ReadRecordsRequest con ExerciseSessionRecord come tipo. In genere, questo viene filtrato in base a un intervallo di tempo specifico.
suspend fun readExerciseSessions(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = ExerciseSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (exerciseRecord in response.records) {
// Process each session
val exerciseType = exerciseRecord.exerciseType
val notes = exerciseRecord.notes
}
}
Leggere i percorsi
Sebbene i dati ExerciseRoute vengano scritti come parte di una sessione di allenamento, devono essere letti separatamente. Utilizza il metodo getExerciseRoute() con l'ID della sessione per leggere i dati del percorso:
suspend fun readExerciseRoute(
healthConnectClient: HealthConnectClient,
exerciseSessionRecord: ExerciseSessionRecord
) {
// Check if the session has a route
val route = healthConnectClient.getExerciseRoute(
exerciseSessionRecordId = exerciseSessionRecord.metadata.id
)
when (route) {
is ExerciseRouteResponse.Success -> {
val locations = route.exerciseRoute.locations
for (location in locations) {
// Use latitude, longitude, and altitude
}
}
is ExerciseRouteResponse.NoData -> {
// Handle case where no route exists
}
is ExerciseRouteResponse.ConsentRequired -> {
// Handle case where permissions are missing
}
}
}
Leggere i tipi di dati
Per leggere dati granulari specifici (come la frequenza cardiaca) che si sono verificati durante una sessione, utilizza startTime e endTime della sessione per filtrare la richiesta per quel tipo di dati.
suspend fun readHeartRateData(
healthConnectClient: HealthConnectClient,
exerciseSession: ExerciseSessionRecord
) {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = HeartRateRecord::class,
timeRangeFilter = TimeRangeFilter.between(
exerciseSession.startTime,
exerciseSession.endTime
)
)
)
for (heartRateRecord in response.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
WorkManagerper le scritture posticipate. 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 e i punti del percorso: per ridurre il sovraccarico di input/output e preservare la durata della batteria, raggruppa i punti dati in una singola
insertRecordsanziché 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 unclientRecordIdgià esistente, Health Connect ignorerà il duplicato o aggiornerà il record esistente anziché crearne uno nuovo. L'impostazione di unmetadata.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.
- Convalida la precisione del GPS: filtra i campioni GPS a bassa precisione (ad esempio, i punti con un raggio di precisione orizzontale elevato) prima di scrivere in
ExerciseRouteper verificare che la mappa sia pulita e professionale. - 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.createIntentper spiegare perché la tua app ha bisogno di accedere ai dati sulla salute, ad esempio: "Per monitorare le tendenze della pressione sanguigna e fornire informazioni". - Supporta la pausa e la ripresa: verifica che la tua app gestisca correttamente le pause. Quando un utente mette in pausa, interrompi la raccolta dei punti del percorso e dei tipi di dati in modo che la velocità media e la durata rimangano accurate.
- 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 di allenamento include in genere:
| Componente | Gestisce |
|---|---|
| Controller sessione | Stato della sessione Timer Logica di batch Controller dei tipi di dati Campionamento della posizione |
| Livello repository (esegue il wrapping delle operazioni di Health Connect): | Inserisci sessione Inserisci tipi di dati Inserisci punti del percorso Leggi i riepiloghi delle sessioni |
| Livello UI (visualizza): | Durata Tipi di dati in tempo reale Anteprima mappa Calcoli divisi Traccia GPS in tempo reale |
Risoluzione dei problemi
| Sintomo | Possibile causa | Risoluzione |
|---|---|---|
| Percorso non associato alla sessione | Mancata corrispondenza tra ID sessione o intervallo di tempo. | Verifica che ExerciseRoute sia scritto con un intervallo di tempo che rientra interamente nella durata di ExerciseSessionRecord. Verifica di utilizzare ID coerenti se fai riferimento alla sessione in un secondo momento. Vedi Registrare i percorsi di allenamento. |
| 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 GPS registrato | Il servizio in primo piano è stato interrotto o è inattivo. | Per raccogliere dati con lo schermo spento, devi utilizzare un servizio in primo piano con l'attributo foregroundServiceType="health" o location. |
| 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". |