Jeśli chcesz w swojej aplikacji utworzyć funkcję monitorowania snu, możesz użyć Health Connect do takich czynności jak:
- Zapisuj sesje snu
- Zapisywanie danych o fazie snu
- Zapisuj dane o śnie, takie jak tętno, saturacja i częstość oddychania
- Odczytywanie danych o śnie z innych aplikacji
Z tego przewodnika dowiesz się, jak tworzyć te funkcje związane ze snem. Znajdziesz w nim informacje o typach danych, wykonywaniu w tle, uprawnieniach, zalecanych przepływach pracy i sprawdzonych metodach.
Omówienie: tworzenie kompleksowego trackera snu
Aby utworzyć kompleksową funkcję monitorowania snu 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ą
SleepSessionRecord. - zapisywanie typów danych, takich jak fazy snu, tętno i poziom saturacji, w sposób ciągły podczas sesji;
- Prawidłowe zarządzanie wykonywaniem w tle w celu weryfikacji ciągłego rejestrowania danych w nocy.
- Odczytywanie danych sesji snu na potrzeby podsumowań i analiz po śnie.
Ten proces umożliwia interoperacyjność z innymi aplikacjami Health Connect i weryfikuje dostęp do danych kontrolowany przez użytkownika.
Zanim zaczniesz
Zanim wdrożysz funkcje związane ze snem:
- 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ń Zdrowia.
Kluczowych pojęć
Health Connect przedstawia dane o śnie za pomocą kilku podstawowych komponentów. A
SleepSessionRecord jest centralnym zapisem snu, zawierającym szczegóły takie jak czas rozpoczęcia i zakończenia oraz fazy snu. Podczas sesji można rejestrować różne typy danych, np. HeartRateRecord lub OxygenSaturationRecord.
Sesje snu
Dane o śnie są reprezentowane przez SleepSessionRecord. Każdy rekord zawiera:
startTimeendTimestages: listaSleepSessionRecord.Stage, w tym sen głęboki, płytki, REM i czuwanie.- Opcjonalne metadane sesji (tytuł, notatki)
Aplikacje mogą zapisywać wiele typów danych powiązanych z sesją.
Typy danych
Typowe rodzaje danych rejestrowanych podczas sesji snu to:
SleepSessionRecord: rejestruje czas trwania i fazy snu, w tym sen głęboki, płytki, REM i czuwanie.HeartRateRecord– rejestruje tętno podczas snu.OxygenSaturationRecord: rejestruje nasycenie tlenem (SpO2) podczas snu.RespiratoryRateRecord: rejestruje częstość oddychania podczas snu.
Każdy typ danych jest przechowywany jako osobny rekord.
Uwagi dotyczące programowania
Aplikacje do monitorowania snu często muszą działać przez dłuższy czas, zwykle w tle, gdy ekran jest wyłączony. Podczas tworzenia funkcji związanych ze snem ważne jest, aby zastanowić się, jak zarządzać wykonywaniem w tle i poprosić o niezbędne uprawnienia do danych o śnie.
Wykonywanie w tle
Aplikacje do monitorowania snu działają zwykle w nocy przy wyłączonym ekranie. W takim przypadku należy używać:
- Usługi działające na pierwszym planie do zbierania danych
WorkManagerw przypadku odroczonego zapisu lub synchronizacji;- Strategie przetwarzania wsadowego w przypadku regularnego zapisywania szczegółowych danych, takich jak tętno
Zachowaj ciągłość, utrzymując spójność identyfikatora sesji we wszystkich operacjach zapisu.
Uprawnienia
Przed odczytaniem lub zapisaniem danych o śnie aplikacja musi poprosić o odpowiednie uprawnienia Health Connect. Pełną listę typów danych znajdziesz w artykule Typy danych w Health Connect. Typowe uprawnienia dotyczące snu obejmują sesje snu i dane takie jak tętno czy saturacja krwi.
Dostęp do informacji o śnie jest chroniony przez te uprawnienia:
android.permission.health.READ_SLEEPandroid.permission.health.WRITE_SLEEP
Aby dodać do aplikacji funkcję monitorowania snu, zacznij od poproszenia o uprawnienia do typu danych SleepSession.
Aby móc zapisywać dane dotyczące snu, musisz zadeklarować to uprawnienie:
<application>
<uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>
Aby odczytywać dane o śnie, musisz poprosić o te uprawnienia:
<application>
<uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>
Poniżej znajdziesz przykład żądania uprawnień do sesji snu, która obejmuje dane dotyczące tętna, saturacji i częstości oddychania:
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(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)
)
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.
Wdrażanie sesji snu
W tej sekcji opisujemy zalecany proces rejestrowania danych o śnie.
Aby dopasować typy danych, takie jak HeartRateRecord lub OxygenSaturationRecord, do sesji snu, rejestruj je ze znacznikami czasu, które mieszczą się między startTime a endTime sesji. Health Connect nie używa identyfikatora sesji do łączenia sesji snu z szczegółowymi danymi. Zamiast tego powiązanie jest domyślne w przypadku nakładających się przedziałów czasowych. Podczas odczytywania danych o śnie możesz użyć zakresu czasu sesji, aby wysłać zapytanie o powiązane typy danych, jak pokazano w sekcji Odczytywanie danych o śnie.
Zapisywanie sesji
Szczegółowe dane, takie jak tętno, mogą być rejestrowane przez cały czas trwania sesji snu, ale SleepSessionRecord musi być zapisywany w Health Connect dopiero po zakończeniu sesji, np. gdy użytkownik się obudzi. Rekord musi zawierać sesję startTime, endTime i listę obiektów SleepSessionRecord.Stage zarejestrowanych podczas sesji, ponieważ SleepSessionRecord wymaga, aby endTime występowało po startTime.
Aby zapisać sesję snu:
- Wygeneruj unikalny identyfikator rekordu klienta.
- Gdy użytkownik się obudzi lub monitorowanie snu zostanie zatrzymane, zbierz wszystkie fazy snu i utwórz
SleepSessionRecord. - Wstaw rekord za pomocą narzędzia
insertRecords.
Przykład:
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))
Odczytywanie danych o śnie
Aplikacje mogą odczytywać sesje snu 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ć SleepSessionRecord, a potem wysłać zapytanie o HeartRateRecord, które wystąpiły w tym samym przedziale czasu.
Sesja odczytu z powiązanymi danymi
Sesje snu możesz odczytywać za pomocą ReadRecordsRequest z SleepSessionRecord jako typem rekordu, filtrowanym według zakresu czasu. Aby odczytać powiązane dane z danej sesji, wyślij drugie żądanie dotyczące wybranego typu danych, np. HeartRateRecord – filtrując według startTime i endTime sesji snu.
Ten przykład pokazuje, jak odczytać sesje snu z powiązanymi danymi o tętnie w określonym zakresie czasu:
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
}
}
}
}
Sprawdzone metody
Aby zwiększyć wiarygodność danych i poprawić wygodę użytkowników, postępuj zgodnie z tymi wskazówkami:
- Częstotliwość zapisu
- Aktywne monitorowanie snu(na pierwszym planie): W przypadku aktywnego monitorowania snu zapisuj dane, gdy tylko staną się dostępne, lub w maksymalnym interwale 15 minut.
- Synchronizacja w tle: używaj
WorkManagerdo odroczonych zapisów. Ustaw interwał 15-minutowy, aby zachować równowagę między danymi w czasie rzeczywistym a wydajnością baterii. - 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 nowej, osobnej sesji snu.
- Używaj przetwarzania wsadowego w przypadku typów danych: aby zmniejszyć obciążenie wejścia/wyjścia i wydłużyć czas pracy 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 = RespiratoryRateRecord( rate = 16.0, time = time, zoneOffset = ZoneOffset.UTC, metadata = Metadata( // Use a unique ID from your own database clientRecordId = "respiratory_rate_20231030_1" ) )Sprawdź istniejące dane: przed synchronizacją wyślij zapytanie dotyczące zakresu czasu, aby sprawdzić, czy rekordy z Twojej aplikacji już istnieją.
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 procesu
Permission.createIntent, aby wyjaśnić, dlaczego Twoja aplikacja potrzebuje dostępu do danych o zdrowiu, np. „Aby analizować wzorce snu”.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 nagrań do rzeczywistej częstotliwości czujników, aby zachować wysoką wierność 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
Wdrożenie monitorowania snu zwykle obejmuje:
| Komponent | Zarządza |
|---|---|
| Kontroler sesji | Stan sesji Timer Logika przetwarzania wsadowego Kontrolery typów danych Zbieranie danych |
| Warstwa repozytorium (zawiera operacje Health Connect): | Wstawianie sesji Wstawianie typów danych Wstawianie faz snu Odczytywanie podsumowań sesji |
| Warstwa interfejsu (wyświetlacze): | Czas trwania Typy danych na żywo Wizualizacja faz snu |
Rozwiązywanie problemów
| Krótki opis problemu | Możliwa przyczyna | Rozdzielczość |
|---|---|---|
| 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 danych z czujników zarejestrowanych podczas snu | Usługa na pierwszym planie została zamknięta lub jest nieaktywna. | Aby zbierać dane z czujników w nocy, gdy ekran jest wyłączony, możesz użyć usługi pierwszego planu z foregroundServiceType="health". |
| 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”.