Ten przewodnik jest zgodny z Health Connect w wersji 1.1.0-alpha11.
Health Connect udostępnia typ danych planowany trening, który umożliwia aplikacjom treningowym zapisywanie planów treningowych i aplikacjom do ćwiczeń odczytywanie planów treningowych. Zapisane treningi można odczytać w celu spersonalizowanej analizy wyników, aby pomóc użytkownikom w osiąganiu celów treningowych.
Dostępność funkcji
Aby sprawdzić, czy urządzenie użytkownika obsługuje plany szkoleniowe w Health Connect, sprawdź dostępność FEATURE_PLANNED_EXERCISE
na kliencie:
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 planów treningowych jest chroniony przez te uprawnienia:
android.permission.health.READ_PLANNED_EXERCISE
android.permission.health.WRITE_PLANNED_EXERCISE
Zadeklaruj te uprawnienia w Konsoli Play dla swojej aplikacji, a także w pliku manifestu aplikacji:
<application>
<uses-permission
android:name="android.permission.health.READ_PLANNED_EXERCISE" />
<uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>
Użytkownik jest odpowiedzialny za zadeklarowanie wszystkich odpowiednich uprawnień, których zamierza używać na urządzeniach i w aplikacjach. Przed użyciem musisz też sprawdzić, czy użytkownik przyznał Ci odpowiednie uprawnienia.
Powiązane uprawnienia
Plany treningowe są powiązane z sesjami ćwiczeń. Aby w pełni korzystać z tej funkcji Health Connect, użytkownik musi zezwolić na używanie każdego typu rekordu związanego z planem szkoleniowym.
Jeśli na przykład plan treningowy mierzy tętno użytkownika podczas serii biegów, deweloper może być zobowiązany do zadeklarowania tych uprawnień i przyznania ich przez użytkownika, aby zapisać sesję ćwiczeń i odczytać wyniki w celu późniejszej oceny:
android.permission.health.READ_EXERCISE
android.permission.health.READ_EXERCISE_ROUTE
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 ich skuteczność, nie jest tą samą aplikacją, która korzysta z planów treningowych i zapisuje dane dotyczące rzeczywistych ćwiczeń. W zależności od typu aplikacji nie wszystkie uprawnienia odczytu i zapisu będą potrzebne. Na przykład w przypadku każdego typu aplikacji mogą być potrzebne tylko te uprawnienia:
Aplikacja z planem treningowym | Aplikacja do treningu |
---|---|
WRITE_PLANNED_EXERCISE |
READ_PLANNED_EXERCISE |
READ_EXERCISE |
WRITE_EXERCISE |
READ_EXERCISE_ROUTE |
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.
- Uwagi dotyczące aktywności.
- Metadane
- Identyfikator ukończonej sesji ćwiczeń – jest zapisywany automatycznie po zakończeniu sesji ćwiczeń powiązanej z tą zaplanowaną sesją ćwiczeń.
Informacje zawarte w rejestrze zaplanowanego bloku ćwiczeń
Zaplanowany blok ćwiczeń zawiera listę ćwiczeń, które można powtarzać w różnych grupach (np. 5 razy z rzędu wykonać sekwencję ćwiczeń na bicepsy, burpee i skłony tułowi).
- Opis bloku.
- lista zaplanowanych kroków ćwiczenia.
- Liczba powtórzeń.
Informacje zawarte w rekordzie zaplanowanego kroku ćwiczenia
- Opis kroku.
- Kategoria ćwiczenia.
- Typ ćwiczenia.
- lista celów skuteczności.
- Cel dotyczący ukończenia.
Obsługiwane agregacje
W przypadku tego typu danych nie ma obsługiwanych agregacji.
Przykład użycia
Załóżmy, że użytkownik planuje 90-minutowy bieg za 2 dni. W ramach tego biegu wykonasz 3 okrążenia wokół jeziora z docelowym tętnem w zakresie 90–110 uderzeń na minutę.
- W aplikacji z planem treningowym użytkownik definiuje zaplanowaną sesję ćwiczeń:
- planowany początek i koniec biegu,
- Typ ćwiczenia (bieg)
- Liczba okrążeń (powtórzeń)
- Docelowy wynik tętna (między 90 a 110 uderzeń na minutę)
- Informacje te są grupowane w bloki ćwiczeń i kroki, a następnie zapisywane w Health Connect przez aplikację z planem treningowym jako
PlannedExerciseSessionRecord
. - Użytkownik wykonuje zaplanowaną sesję (bieg).
- Dane dotyczące ćwiczeń związane z sesją są rejestrowane w ten sposób:
- 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 wskazujące początek i koniec rzeczywistego wykonania. 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 docelami określonymi przez użytkownika w planowanej sesji ćwiczeń.
Planowanie ćwiczeń i ustalanie celów
Użytkownik może zaplanować ćwiczenia na przyszłość i ustawić cele. Zapisz to w Health Connect jako planowaną sesję ćwiczeń.
W przykładzie opisanym w sekcji Przykładowe zastosowanie użytkownik planuje 90-minutowy bieg za 2 dni. W ramach tego treningu wykonasz 3 okrążenia wokół jeziora z docelowym tętnem w zakresie 90–110 uderzeń na minutę.
Taki fragment kodu możesz znaleźć w obiekcie obsługującym formularz w aplikacji, która rejestruje zaplanowane sesje ćwiczeń w Health Connect. Może się ona też znajdować w najlepszym miejscu na potrzeby integracji, np. z usługą, która oferuje szkolenia.
// Ensure 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 = ExerciseSessionRecord.EXERCISE_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
)
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 informacje w Health Connect jako sesję ćwiczeń.
W tym przykładzie czas trwania sesji użytkownika dokładnie odpowiadał zaplanowanemu czasowi.
Ten fragment kodu może znajdować się w obiekcie obsługującym formularz w aplikacji, która rejestruje sesje ćwiczeń w Health Connect. Może się ona też znajdować w elementach obsługi importowania i eksportowania danych w przypadku urządzeń noszonych, które są w stanie wykrywać i rejestrować sesje ćwiczeń.
Wartość insertedPlannedExerciseSessionId
jest tu ponownie użyta z poprzedniego przykładu. W prawdziwej aplikacji identyfikator jest określany przez użytkownika, który wybiera zaplanowany trening z listy istniejących treningów.
// Ensure 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,
)
val insertedExerciseSessions =
healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
Urządzenie noszone rejestruje również tętno podczas biegu. Do generowania rekordów w zakresie docelowym można użyć tego fragmentu kodu.
W rzeczywistej aplikacji główne elementy tego fragmentu kodu można znaleźć w obiekcie obsługującym dla wiadomości z urządzenia do noszenia, który po zebraniu danych zapisze je w Health Connect.
// Ensure 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,
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))
Ocena celów skuteczności
Dzień po treningu użytkownika możesz pobrać zarejestrowany trening, sprawdzić zaplanowane cele treningowe i przeanalizować dodatkowe typy danych, aby określić, czy cele zostały osiągnięte.
Taki fragment kodu znajdziesz prawdopodobnie w okresowym zadaniu służącym do oceny celów skuteczności lub podczas wczytywania listy ćwiczeń i wyświetlania powiadomienia o celach skuteczności w aplikacji.
// Ensure 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
}
}
}
}
}
}
}
}