Ten przewodnik jest zgodny z wersją Health Connect 1.1.0-alpha11.
Health Connect udostępnia typ danych zaplanowane ćwiczenia, aby umożliwić aplikacjom do treningu zapisywanie planów treningowych, a aplikacjom do ćwiczeń odczytywanie tych planów. Zarejestrowane ćwiczenia (treningi) można odczytywać w celu spersonalizowanej analizy wydajności, aby pomagać użytkownikom w osiąganiu celów treningowych.
Dostępność funkcji
Aby sprawdzić, czy urządzenie użytkownika obsługuje plany treningowe w Health Connect, sprawdź dostępnośćFEATURE_PLANNED_EXERCISE
w aplikacji:
if (healthConnectClient
.features
.getFeatureStatus(
HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {
// Feature is available
} else {
// Feature isn't available
}
Więcej informacji znajdziesz w sekcji Sprawdzanie dostępności funkcji.
Wymagane uprawnienia
Dostęp do zaplanowanych ćwiczeń jest chroniony przez te uprawnienia:
android.permission.health.READ_PLANNED_EXERCISE
android.permission.health.WRITE_PLANNED_EXERCISE
Aby dodać do aplikacji możliwość planowania ćwiczeń, zacznij od poproszenia o uprawnienia do zapisu w przypadku typu danych PlannedExerciseSession
.
Aby móc zapisywać zaplanowane ćwiczenia, musisz zadeklarować to uprawnienie:
<application>
<uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>
Aby odczytać zaplanowane ćwiczenie, musisz poprosić o te uprawnienia:
<application>
<uses-permission
android:name="android.permission.health.READ_PLANNED_EXERCISE" />
...
</application>
Prośba użytkownika o uprawnienia
Po utworzeniu instancji klienta aplikacja musi poprosić użytkownika o przyznanie uprawnień. Użytkownicy muszą mieć możliwość przyznania lub odmowy przyznania uprawnień w dowolnym momencie.
Aby to zrobić, utwórz zestaw uprawnień dla wymaganych typów danych. Sprawdź, czy uprawnienia w zestawie są najpierw zadeklarowane w pliku manifestu Androida.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class),
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Użyj getGrantedPermissions
, aby sprawdzić, czy Twoja aplikacja ma już przyznane wymagane uprawnienia. Jeśli nie, użyj createRequestPermissionResultContract
, aby poprosić o te uprawnienia. Wyświetli się ekran uprawnień 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)
}
}
Użytkownicy mogą w dowolnym momencie przyznawać i wycofywać uprawnienia, dlatego aplikacja musi okresowo sprawdzać, czy uprawnienia zostały przyznane, i obsługiwać sytuacje, w których uprawnienia zostaną utracone.
Powiązane uprawnienia
Plany treningowe są powiązane z sesjami ćwiczeń. Dlatego użytkownik musi zezwolić na używanie każdego typu rekordu związanego z planem treningowym, aby w pełni korzystać z tej funkcji Health Connect.
Jeśli na przykład plan treningowy mierzy tętno użytkownika podczas serii biegów, deweloper może musieć zadeklarować te uprawnienia, a użytkownik może musieć je przyznać, aby zapisać sesję ćwiczeń i odczytać wyniki do późniejszej oceny:
android.permission.health.READ_EXERCISE
android.permission.health.READ_EXERCISE_ROUTES
android.permission.health.READ_HEART_RATE
android.permission.health.WRITE_EXERCISE
android.permission.health.WRITE_EXERCISE_ROUTE
android.permission.health.WRITE_HEART_RATE
Często jednak aplikacja, która tworzy plany treningowe i ocenia skuteczność na ich podstawie, nie jest tą samą aplikacją, która korzysta z planów treningowych i zapisuje rzeczywiste dane o ćwiczeniach. W zależności od typu aplikacji nie wszystkie uprawnienia do odczytu i zapisu będą potrzebne. Na przykład w przypadku poszczególnych typów aplikacji możesz potrzebować tylko tych uprawnień:
Aplikacja z planem treningowym | Aplikacja do ćwiczeń |
---|---|
WRITE_PLANNED_EXERCISE |
READ_PLANNED_EXERCISE |
READ_EXERCISE |
WRITE_EXERCISE |
READ_EXERCISE_ROUTES |
WRITE_EXERCISE_ROUTE |
READ_HEART_RATE |
WRITE_HEART_RATE |
Informacje zawarte w rekordzie zaplanowanej sesji ćwiczeń
- Tytuł sesji.
- Lista zaplanowanych bloków ćwiczeń.
- czas rozpoczęcia i zakończenia sesji;
- Typ ćwiczenia.
- Notatki dotyczące aktywności.
- Metadane
- Identyfikator ukończonej sesji ćwiczeń – jest zapisywany automatycznie po ukończeniu sesji ćwiczeń powiązanej z tą zaplanowaną sesją.
Informacje zawarte w rekordzie zaplanowanego bloku ćwiczeń
Zaplanowany blok ćwiczeń zawiera listę kroków ćwiczeń, które umożliwiają powtarzanie różnych grup kroków (np. wykonanie 5 razy z rzędu sekwencji ugięć ramion, burpees i brzuszków).
- Opis bloku.
- Lista zaplanowanych kroków ćwiczeń.
- Liczba powtórzeń.
Informacje zawarte w rekordzie zaplanowanego kroku ćwiczenia
- Opis kroku.
- Kategoria ćwiczenia.
- Typ ćwiczenia
- Lista celów skuteczności.
- Cel ukończenia
Obsługiwane agregacje
W przypadku tego typu danych nie ma obsługiwanych agregacji.
Przykład użycia
Załóżmy, że użytkownik zaplanował 90-minutowy bieg za 2 dni. Ten bieg będzie obejmować 3 okrążenia wokół jeziora z docelowym tętnem od 90 do 110 uderzeń na minutę.
- Zaplanowana sesja ćwiczeń z tymi parametrami jest definiowana przez użytkownika w aplikacji do planowania treningów:
- Planowany początek i koniec biegu
- Rodzaj ćwiczenia (bieganie)
- Liczba okrążeń (powtórzeń)
- Docelowe tętno (90–110 uderz./min)
- Te informacje są grupowane w bloki ćwiczeń i kroków, a następnie zapisywane w Health Connect przez aplikację planu treningowego jako
PlannedExerciseSessionRecord
. - Użytkownik przeprowadza zaplanowaną sesję (bieganie).
- Dane ćwiczeń związane z sesją są rejestrowane w jeden z tych sposobów:
- przez urządzenie do noszenia podczas sesji; Na przykład tętno.
Te dane są zapisywane w Health Connect jako typ rekordu aktywności. W tym przypadku
HeartRateRecord
. - ręcznie przez użytkownika po zakończeniu sesji; Na przykład wskazanie początku i końca rzeczywistego biegu. Te dane są zapisywane w Health Connect jako
ExerciseSessionRecord
.
- przez urządzenie do noszenia podczas sesji; Na przykład tętno.
Te dane są zapisywane w Health Connect jako typ rekordu aktywności. W tym przypadku
- Później aplikacja z planem treningowym odczytuje dane z Health Connect, aby ocenić rzeczywiste wyniki w porównaniu z celami wyznaczonymi przez użytkownika w zaplanowanej sesji ćwiczeń.
Planowanie ćwiczeń i wyznaczanie celów
Użytkownik może zaplanować ćwiczenia na przyszłość i ustawić cele. Zapisz to w Health Connect jako zaplanowaną sesję ćwiczeń.
W przykładzie opisanym w sekcji Przykładowe użycie użytkownik planuje 90-minutowy bieg za 2 dni. Ten bieg będzie obejmować 3 okrążenia wokół jeziora z docelowym tętnem od 90 do 110 uderzeń na minutę.
Fragment kodu podobny do tego może znajdować się w programie obsługi formularzy aplikacji, która rejestruje zaplanowane sesje ćwiczeń w Health Connect. Może się też znajdować w punkcie odbioru danych na potrzeby integracji, np. z usługą oferującą szkolenia.
// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class))) {
// The user hasn't granted the app permission to write planned exercise session data.
return
}
val plannedDuration = Duration.ofMinutes(90)
val plannedStartDate = LocalDate.now().plusDays(2)
val plannedExerciseSessionRecord = PlannedExerciseSessionRecord(
startDate = plannedStartDate,
duration = plannedDuration,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
blocks = listOf(
PlannedExerciseBlock(
repetitions = 1, steps = listOf(
PlannedExerciseStep(
exerciseType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING,
exercisePhase = PlannedExerciseStep.EXERCISE_PHASE_ACTIVE,
completionGoal = ExerciseCompletionGoal.RepetitionsGoal(repetitions = 3),
performanceTargets = listOf(
ExercisePerformanceTarget.HeartRateTarget(
minHeartRate = 90.0, maxHeartRate = 110.0
)
)
),
), description = "Three laps around the lake"
)
),
title = "Run at lake",
notes = null,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
val insertedPlannedExerciseSessions =
healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)).recordIdsList
val insertedPlannedExerciseSessionId = insertedPlannedExerciseSessions.first()
Zapisywanie danych o ćwiczeniach i aktywności
Dwa dni później użytkownik rejestruje rzeczywistą sesję ćwiczeń. Zapisz te dane w Health Connect jako sesję ćwiczeń.
W tym przykładzie czas trwania sesji użytkownika dokładnie odpowiadał zaplanowanemu czasowi trwania.
Poniższy fragment kodu może znajdować się w programie obsługi formularzy aplikacji, która rejestruje sesje ćwiczeń w Health Connect. Może się też znajdować w programach do pozyskiwania i eksportowania danych na urządzeniu do noszenia, które wykrywa i rejestruje sesje ćwiczeń.
insertedPlannedExerciseSessionId
jest ponownie używana z poprzedniego przykładu. W prawdziwej aplikacji identyfikator byłby określany przez użytkownika, który wybiera zaplanowaną sesję ćwiczeń z listy istniejących sesji.
// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
HealthPermission.getWritePermission(ExerciseSessionRecord::class))) {
// The user doesn't granted the app permission to write exercise session data.
return
}
val sessionDuration = Duration.ofMinutes(90)
val sessionEndTime = Instant.now()
val sessionStartTime = sessionEndTime.minus(sessionDuration)
val exerciseSessionRecord = ExerciseSessionRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
segments = listOf(
ExerciseSegment(
startTime = sessionStartTime,
endTime = sessionEndTime,
repetitions = 3,
segmentType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING
)
),
title = "Run at lake",
plannedExerciseSessionId = insertedPlannedExerciseSessionId,
metadata = Metadata.manualEntry(
device = Device(type = Device.Companion.TYPE_PHONE)
)
)
val insertedExerciseSessions =
healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
Urządzenie do noszenia rejestruje też tętno podczas biegu. Poniższy fragment kodu może służyć do generowania rekordów w zakresie docelowym.
W prawdziwej aplikacji główne elementy tego fragmentu kodu mogą znajdować się w procedurze obsługi wiadomości z urządzenia do noszenia, która po zebraniu danych zapisuje pomiary w Health Connect.
// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
HealthPermission.getWritePermission(HeartRateRecord::class))) {
// The user doesn't granted the app permission to write heart rate record data.
return
}
val samples = mutableListOf<HeartRateRecord.Sample>()
var currentTime = sessionStartTime
while (currentTime.isBefore(sessionEndTime)) {
val bpm = Random.nextInt(21) + 90
val heartRateRecord = HeartRateRecord.Sample(
time = currentTime,
beatsPerMinute = bpm.toLong(),
)
samples.add(heartRateRecord)
currentTime = currentTime.plusSeconds(180)
}
val heartRateRecord = HeartRateRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
samples = samples,
metadata = Metadata.autoRecorded(
device = Device(type = Device.Companion.TYPE_WATCH)
)
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))
Ocena celów skuteczności
Następnego dnia po treningu użytkownika możesz pobrać zarejestrowane ćwiczenie, sprawdzić, czy są jakieś zaplanowane cele ćwiczeń, i ocenić dodatkowe typy danych, aby określić, czy ustawione cele zostały osiągnięte.
Taki fragment kodu można znaleźć w zadaniu okresowym, które służy do oceny celów skuteczności, lub podczas wczytywania listy ćwiczeń i wyświetlania w aplikacji powiadomienia o celach skuteczności.
// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.containsAll(
listOf(
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
HealthPermission.getReadPermission(HeartRateRecord::class)
)
)
) {
// The user doesn't granted the app permission to read exercise session record data.
return
}
val searchDuration = Duration.ofDays(1)
val searchEndTime = Instant.now()
val searchStartTime = searchEndTime.minus(searchDuration)
val response = healthConnectClient.readRecords(
ReadRecordsRequest<ExerciseSessionRecord>(
timeRangeFilter = TimeRangeFilter.between(searchStartTime, searchEndTime)
)
)
for (exerciseRecord in response.records) {
val plannedExerciseRecordId = exerciseRecord.plannedExerciseSessionId
val plannedExerciseRecord =
if (plannedExerciseRecordId == null) null else healthConnectClient.readRecord(
PlannedExerciseSessionRecord::class, plannedExerciseRecordId
).record
if (plannedExerciseRecord != null) {
val aggregateRequest = AggregateRequest(
metrics = setOf(HeartRateRecord.BPM_AVG),
timeRangeFilter = TimeRangeFilter.between(
exerciseRecord.startTime, exerciseRecord.endTime
),
)
val aggregationResult = healthConnectClient.aggregate(aggregateRequest)
val maxBpm = aggregationResult[HeartRateRecord.BPM_MAX]
val minBpm = aggregationResult[HeartRateRecord.BPM_MIN]
if (maxBpm != null && minBpm != null) {
plannedExerciseRecord.blocks.forEach { block ->
block.steps.forEach { step ->
step.performanceTargets.forEach { target ->
when (target) {
is ExercisePerformanceTarget.HeartRateTarget -> {
val minTarget = target.minHeartRate
val maxTarget = target.maxHeartRate
if(
minBpm >= minTarget && maxBpm <= maxTarget
) {
// Success!
}
}
// Handle more target types
}
}
}
}
}
}
}
}