Jeśli chcesz w swojej aplikacji stworzyć jakość treningu, możesz użyć Health Connect do takich czynności jak:
- Zapisywanie sesji ćwiczeń
- Zapisywanie tras treningowych
- Zapisuj dane treningowe, takie jak tętno, prędkość i dystans
- Odczytywanie danych o treningach z innych aplikacji
Z tego przewodnika dowiesz się, jak tworzyć te funkcje treningowe. Znajdziesz w nim informacje o typach danych, wykonywaniu w tle, uprawnieniach, zalecanych przepływach pracy i sprawdzonych metodach.
Omówienie: tworzenie kompleksowego trackera treningów
Aby stworzyć kompleksowe rozwiązanie do śledzenia treningów za pomocą Health Connect, wykonaj te podstawowe czynności:
- prawidłowe wdrażanie uprawnień na podstawie uprawnień związanych ze zdrowiem;
- Nagrywanie sesji za pomocą
ExerciseSessionRecord. - zapisywanie danych treningowych w spójny sposób podczas sesji;
- Prawidłowe zarządzanie wykonywaniem w tle w celu weryfikacji ciągłego zbierania danych.
- Odczytywanie danych sesji na potrzeby podsumowań i analiz po treningu.
Ten proces umożliwia interoperacyjność z innymi aplikacjami Health Connect i weryfikuje dostęp do danych kontrolowany przez użytkownika.
Zanim zaczniesz
Przed wdrożeniem funkcji treningu:
- Zintegruj Health Connect, korzystając z odpowiedniej zależności.
- Utwórz instancję
HealthConnectClient. - Sprawdź, czy aplikacja implementuje przepływy uprawnień w czasie działania na podstawie uprawnień związanych ze zdrowiem.
- Jeśli Twój proces korzysta z GPS-u, skonfiguruj dostęp do lokalizacji i usługę na pierwszym planie.
Kluczowych pojęć
Health Connect reprezentuje dane o treningu za pomocą kilku podstawowych komponentów. ExerciseSessionRecord jest centralnym rekordem treningu,ExerciseSessionRecord zawierającym szczegóły takie jak czas rozpoczęcia i zakończenia oraz rodzaj ćwiczenia. Podczas sesji można rejestrować różne typy danych, np. HeartRateRecord lub SpeedRecord. W przypadku aktywności na zewnątrz ExerciseRoute przechowuje dane GPS, które są powiązane z odpowiednią sesją.
Sesje ćwiczeń
ExerciseSessionRecord to centralny rekord danych treningowych, który reprezentuje pojedynczą sesję treningową. Każdy rekord zawiera:
startTimeendTimeexerciseType- Opcjonalne metadane sesji (tytuł, notatki)
ExerciseSessionRecord może też zawierać trasy ćwiczeń, okrążenia i segmenty. Podczas sesji można też rejestrować i powiązywać z nią inne typy danych, np. HeartRateRecord lub SpeedRecord.
Powiązane typy danych
Dane powiązane z sesjami treningowymi są reprezentowane przez poszczególne typy rekordów. Typowe rodzaje:
HeartRateRecord: reprezentuje serię pomiarów tętna.SpeedRecord: reprezentuje serię pomiarów prędkości.DistanceRecord: reprezentuje odległość pokonaną między odczytami.TotalCaloriesBurnedRecord: reprezentuje sumę spalonych kalorii między odczytami.ElevationGainedRecord: reprezentuje wysokość zdobytą między odczytami.StepsCadenceRecord: reprezentuje kadencję kroków między odczytami.PowerRecord: reprezentuje moc wyjściową między odczytami, co jest typowe w przypadku aktywności takich jak jazda na rowerze.
Pełną listę typów danych znajdziesz w artykule Typy danych w Health Connect.
Trasy ćwiczeń
Możesz powiązać trasę z treningami na świeżym powietrzu za pomocą ExerciseRoute. Trasy
składają się z sekwencyjnych obiektów ExerciseRoute.Location, z których każdy zawiera:
- Długość i szerokość geograficzna
- Opcjonalna wysokość
- Opcjonalny namiar
- Informacje o dokładności
- Sygnatura czasowa
Łączenie tras sesji
ExerciseRoute zawiera sekwencyjne dane o lokalizacji dotyczące sesji ćwiczeń. Nie jest traktowany jako niezależny rekord w Health Connect. Zamiast tego podczas wstawiania lub aktualizowania ExerciseRoute danych podajesz ExerciseSessionRecord.
Uwagi dotyczące programowania
Aplikacje do śledzenia treningów często muszą działać przez dłuższy czas, zwykle w tle, gdy ekran jest wyłączony. Podczas tworzenia funkcji treningowych ważne jest, aby zastanowić się, jak zarządzać wykonywaniem w tle i poprosić o niezbędne uprawnienia do danych treningowych.
Wykonywanie w tle
Aplikacje do ćwiczeń często działają przy wyłączonym ekranie. W takim przypadku należy używać:
- Usługi działające na pierwszym planie do pobierania próbek lokalizacji i danych z czujników
WorkManagerw przypadku odroczonego zapisu lub synchronizacji.- Strategie zbiorczego przetwarzania danych w przypadku zwykłego zapisu rekordów
Zachowaj ciągłość, utrzymując spójność identyfikatora sesji we wszystkich operacjach zapisu.
Uprawnienia
Przed odczytaniem lub zapisaniem danych treningu aplikacja musi poprosić o odpowiednie uprawnienia Health Connect. Typowe uprawnienia dotyczące treningów obejmują sesje ćwiczeń, trasy ćwiczeń i dane takie jak tętno czy prędkość. między innymi na następujące działania:
- Sesje ćwiczeń: uprawnienia do odczytu i zapisu w przypadku
ExerciseSessionRecord. - Trasy ćwiczeń: uprawnienia do odczytu i zapisu w przypadku
ExerciseRoute. - Tętno: uprawnienia do odczytu i zapisu w przypadku
HeartRateRecord. - Szybkość: uprawnienia do odczytu i zapisu w przypadku
SpeedRecord. - Odległość: uprawnienia do odczytu i zapisu w przypadku
DistanceRecord. - Kalorie: uprawnienia do odczytu i zapisu dla
TotalCaloriesBurnedRecord. - Zdobyta wysokość: uprawnienia do odczytu i zapisu dla
ElevationGainedRecord. - Kadencja kroków: uprawnienia do odczytu i zapisu dla
StepsCadenceRecord. - Zasilanie: uprawnienia do odczytu i zapisu w przypadku
PowerRecord. - Czynności: uprawnienia do odczytu i zapisu w przypadku
StepsRecord.
Poniższy przykład pokazuje, jak poprosić o wiele uprawnień w przypadku sesji treningowej, która obejmuje dane o trasie, tętnie, odległości, kaloriach, prędkości i krokach:
Po utworzeniu instancji klienta aplikacja musi poprosić użytkownika o uprawnienia. 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(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)
)
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 każdej chwili przyznać lub cofnąć uprawnienia, dlatego aplikacja musi sprawdzać uprawnienia za każdym razem przed ich użyciem i obsługiwać sytuacje, w których uprawnienia zostaną utracone.
Aby poprosić o uprawnienia, wywołaj funkcję 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
Jeśli musisz poprosić o uprawnienia tylko do jednego typu danych, np. tętna, uwzględnij w zbiorze uprawnień tylko ten typ danych:
Dostęp do danych o tętnie jest chroniony przez te uprawnienia:
android.permission.health.READ_HEART_RATEandroid.permission.health.WRITE_HEART_RATE
Aby dodać do aplikacji funkcję pomiaru tętna, zacznij od poproszenia o uprawnienia do typu danych HeartRateRecord.
Aby móc zapisywać dane o tętnie, musisz zadeklarować to uprawnienie:
<application>
<uses-permission
android:name="android.permission.health.WRITE_HEART_RATE" />
...
</application>
Aby odczytać dane o tętnie, musisz poprosić o te uprawnienia:
<application>
<uses-permission
android:name="android.permission.health.READ_HEART_RATE" />
...
</application>
Wdrażanie sesji treningowej
W tej sekcji opisujemy zalecany proces rejestrowania danych treningowych.
Rozpocznij sesję
Aby utworzyć nowy trening:
- Wygeneruj unikalny identyfikator sesji: sprawdź, czy ten identyfikator jest stabilny. Jeśli proces aplikacji zostanie zakończony i ponownie uruchomiony, musisz mieć możliwość wznowienia korzystania z tego samego identyfikatora, aby zapobiec fragmentacji sesji.
- Ustaw
metadata.clientRecordId, aby zapobiec duplikatom podczas ponownych prób synchronizacji. - Wpisz
ExerciseSessionRecord: podaj godzinę rozpoczęcia. - Rozpocznij zbieranie danych o typie danych i danych GPS: zacznij je zbierać dopiero po prawidłowym zainicjowaniu rekordu sesji.
Przykład:
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))
Rejestrowanie tras ćwiczeń
Więcej informacji o wskazówkach dotyczących odczytywania znajdziesz w sekcji Odczytywanie nieprzetworzonych danych.
Podczas rejestrowania trasy ćwiczeń dane należy przesyłać partiami. Oznacza to, że zamiast zapisywać każdy punkt GPS w momencie jego wystąpienia, zbierasz grupę punktów i zapisujesz je wszystkie naraz w ramach jednego wywołania.
Jest to ważne, ponieważ za każdym razem, gdy aplikacja odczytuje lub zapisuje dane w Health Connect, zużywa niewielką ilość baterii i mocy obliczeniowej.
Poniższy kod pokazuje, jak rejestrować dane w partiach:
// 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))
Kończenie sesji
Po zatrzymaniu zbierania danych:
- Aktualizacja rekordu: aplikacja aktualizuje
ExerciseSessionRecordza pomocąendTime. - Kończenie danych: opcjonalnie oblicz wartości podsumowujące (np. łączny dystans lub średnie tempo) i zapisz je jako dodatkowe rekordy.
val finishedSession = session.copy(endTime = Instant.now())
healthConnectClient.updateRecords(listOf(finishedSession))
Odczytywanie danych treningowych
Aplikacje mogą odczytywać sesje ćwiczeń i powiązane z nimi dane, aby podsumowywać aktywność, dostarczać informacji o zdrowiu lub synchronizować dane z serwerem zewnętrznym. Możesz na przykład odczytać ExerciseSessionRecord, a potem wysłać zapytanie o HeartRateRecord lub DistanceRecord, które wystąpiły w tym samym przedziale czasu.
Jeśli chcesz synchronizować dane treningu z serwerem backendu lub aktualizować magazyn danych aplikacji za pomocą Health Connect, użyj ChangeLogs. Umożliwia to pobieranie listy wstawionych, zaktualizowanych lub usuniętych rekordów od określonego momentu, co jest bardziej wydajne niż ręczne śledzenie zmian lub wielokrotne odczytywanie wszystkich danych. Więcej informacji znajdziesz w artykule Synchronizowanie danych z Health Connect.
Odczytywanie sesji
Aby odczytać sesje ćwiczeń, użyj ReadRecordsRequest z typem ExerciseSessionRecord. Zwykle filtrujesz te dane według określonego zakresu czasu.
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
}
}
Odczytywanie tras
Chociaż ExerciseRoute dane są zapisywane w ramach sesji ćwiczeń, muszą być odczytywane oddzielnie. Użyj metody getExerciseRoute() z identyfikatorem sesji, aby odczytać dane o jej trasie:
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
}
}
}
Typy danych odczytu
Aby odczytać szczegółowe dane (np. tętno) z sesji, użyj parametrów startTime i endTime, aby odfiltrować żądanie dotyczące tego typu danych.
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
}
}
}
Sprawdzone metody
Aby zwiększyć wiarygodność danych i poprawić wygodę użytkowników, postępuj zgodnie z tymi wskazówkami:
- Częstotliwość zapisu
- Aktywne śledzenie(na pierwszym planie): w przypadku aktywnych treningów zapisuj dane, gdy staną się dostępne, lub w maksymalnym odstępie 15 minut.
- Synchronizacja w tle: używaj
WorkManagerw przypadku odroczonych zapisów. Aby zachować równowagę między danymi w czasie rzeczywistym a wydajnością baterii, ustaw interwał 15-minutowy. - Grupowanie: nie zapisuj każdego zdarzenia z czujnika osobno. Dziel żądania na mniejsze części. Health Connect obsługuje do 1000 rekordów w jednym żądaniu zapisu.
- Utrzymuj stabilne i unikalne identyfikatory sesji: używaj spójnych identyfikatorów sesji. Jeśli sesja zostanie zmodyfikowana lub zaktualizowana, użycie tego samego identyfikatora zapobiegnie traktowaniu jej jako nowego, oddzielnego treningu.
- Używaj przetwarzania wsadowego w przypadku obu typów danych i punktów trasy: aby zmniejszyć obciążenie wejścia/wyjścia i wydłużyć czas pracy na baterii, grupuj punkty danych w jedno wywołanie
insertRecordszamiast zapisywać każdy punkt osobno. Unikaj zapisywania zduplikowanych danych: używaj identyfikatorów klientów. Podczas tworzenia rekordów ustaw wartość
metadata.clientRecordId. Health Connect używa tego identyfikatora do identyfikowania unikalnych rekordów. Jeśli spróbujesz zapisać rekord zclientRecordId, który już istnieje, Health Connect zignoruje duplikat lub zaktualizuje istniejący rekord zamiast tworzyć nowy. Ustawieniemetadata.clientRecordIdto najskuteczniejszy sposób zapobiegania duplikatom podczas ponownych prób synchronizacji lub ponownej instalacji aplikacji.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" ) )Sprawdź istniejące dane: przed synchronizacją wyślij zapytanie dotyczące zakresu czasu, aby sprawdzić, czy rekordy z Twojej aplikacji już istnieją.
Sprawdzanie dokładności GPS-a: przed zapisaniem w
ExerciseRouteodfiltruj próbki GPS-a o niskiej dokładności (np. punkty o dużym promieniu dokładności poziomej), aby sprawdzić, czy mapa wygląda przejrzyście i profesjonalnie.Sprawdź, czy znaczniki czasu się nie pokrywają: upewnij się, że nowa sesja nie rozpoczyna się przed zakończeniem poprzedniej. Nakładające się sesje mogą powodować konflikty na panelach aktywności i w obliczeniach podsumowujących.
Podaj jasne uzasadnienie uprawnień: użyj przepływu
Permission.createIntent, aby wyjaśnić, dlaczego Twoja aplikacja potrzebuje dostępu do danych o zdrowiu, np. „Aby mapować Twoje biegi i obliczać spalone kalorie”.Obsługa wstrzymywania i wznawiania: sprawdź, czy aplikacja prawidłowo obsługuje wstrzymywanie. Gdy użytkownik wstrzyma aktywność, przestań zbierać punkty trasy i typy danych, aby średnie tempo i czas trwania pozostały dokładne.
Testuj długotrwałe sesje: monitoruj zużycie baterii podczas sesji trwających kilka godzin, aby sprawdzić, czy interwał grupowania i użycie czujników nie wyczerpują baterii urządzenia.
Dopasuj sygnatury czasowe do częstotliwości czujników: dopasuj sygnatury czasowe rekordów do rzeczywistej częstotliwości czujników (np. 1 Hz w przypadku GPS), aby zachować wysoką jakość danych.
Testowanie
Aby sprawdzić poprawność danych i zapewnić wysoką jakość obsługi, postępuj zgodnie z tymi strategiami testowania i zapoznaj się z oficjalną dokumentacją Testowanie najważniejszych przypadków użycia.
Narzędzia do weryfikacji
- Zestaw narzędzi Health Connect: używaj tej aplikacji towarzyszącej, aby ręcznie sprawdzać rekordy, usuwać dane testowe i symulować zmiany w bazie danych. To najlepszy sposób na sprawdzenie, czy rekordy są prawidłowo przechowywane.
- Testy jednostkowe z użyciem
FakeHealthConnectClient: użyj biblioteki testowej, aby sprawdzić, jak aplikacja radzi sobie w sytuacjach skrajnych, takich jak cofnięcie uprawnień lub wyjątki interfejsu API, bez konieczności używania urządzenia fizycznego.
Lista kontrolna jakości
Typowa architektura
Implementacja treningu zwykle obejmuje:
| Komponent | Zarządza |
|---|---|
| Kontroler sesji | Stan sesji Timer Logika przetwarzania wsadowego Kontrolery typów danych Próbkowanie lokalizacji |
| Warstwa repozytorium (zawiera operacje Health Connect): | Wstawianie sesji Wstawianie typów danych Wstawianie punktów trasy Odczytywanie podsumowań sesji |
| Warstwa interfejsu (wyświetlacze): | Czas trwania Typy danych na żywo Podgląd mapy Podział obliczeń Ślad GPS na żywo |
Rozwiązywanie problemów
| Krótki opis problemu | Możliwa przyczyna | Rozdzielczość |
|---|---|---|
| Trasa nie jest powiązana z sesją | Niezgodność identyfikatora sesji lub zakresu czasu. | Sprawdź, czy ExerciseRoute jest zapisany z zakresem czasu, który w całości mieści się w czasie trwania ExerciseSessionRecord. Jeśli później będziesz odwoływać się do sesji, sprawdź, czy używasz spójnych identyfikatorów. Zobacz Nagrywanie tras ćwiczeń. |
| Brakujące typy danych (np. tętno) | Brak uprawnień do zapisu lub nieprawidłowe filtry czasu. | Sprawdź, czy masz uprawnienia do określonego typu danych i czy użytkownik je przyznał. Sprawdź, czy ReadRecordsRequest używa TimeRangeFilter, który pasuje do sesji. Zobacz Uprawnienia. |
| Nie udało się zapisać sesji | Pokrywające się sygnatury czasowe. | Health Connect może odrzucać rekordy, które pokrywają się z istniejącymi danymi z tej samej aplikacji. Sprawdź, czy startTime nowej sesji następuje po endTime poprzedniej. |
| Brak zarejestrowanych danych GPS | Usługa na pierwszym planie została zamknięta lub jest nieaktywna. | Aby zbierać dane przy wyłączonym ekranie, musisz używać usługi pierwszego planu z atrybutem foregroundServiceType="health" lub lokalizacji. |
| Wyświetlają się zduplikowane rekordy | Brak clientRecordId |
Przypisz unikalny clientRecordId w Metadata każdego rekordu. Dzięki temu Health Connect może usuwać duplikaty, jeśli te same dane zostaną zapisane dwukrotnie podczas ponownej próby synchronizacji. Zobacz sprawdzone metody. |
Typowe czynności debugowania
- Sprawdź stan uprawnień: zawsze wywołuj
getPermissionStatus()przed podjęciem próby odczytu lub zapisu. Użytkownicy mogą w dowolnym momencie cofnąć uprawnienia w ustawieniach systemu. - Sprawdź tryb wykonywania: jeśli Twoja aplikacja nie zbiera danych w tle, sprawdź, czy w pliku
AndroidManifest.xmlzadeklarowano prawidłowe uprawnienia i czy użytkownik nie ustawił dla aplikacji trybu „Ograniczenie baterii”.