Odczyt nieprzetworzonych danych

Poniższy przykład pokazuje, jak odczytywać dane pierwotne w ramach typowego procesu.

Odczytywanie danych

Health Connect umożliwia aplikacjom odczytywanie danych z magazynu danych, gdy aplikacja działa na pierwszym planie lub w tle:

  • Odczytywanie na pierwszym planie: zwykle możesz odczytywać dane z Health Connect, gdy aplikacja działa na pierwszym planie. W takich przypadkach możesz użyć usługi działającej na pierwszym planie, aby uruchomić tę operację, jeśli użytkownik lub system przełączy aplikację na działanie w tle podczas operacji odczytu.

  • Odczytywanie w tle: jeśli poprosisz użytkownika o dodatkowe uprawnienia, możesz odczytywać dane po tym, jak użytkownik lub system przełączy aplikację na działanie w tle. Zobacz pełny przykład odczytywania w tle.

Typ danych Steps w Health Connect rejestruje liczbę kroków wykonanych przez użytkownika między odczytami. Liczba kroków to powszechny pomiar na platformach związanych ze zdrowiem, aktywnością fizyczną i dobrym samopoczuciem. Health Connect umożliwia odczytywanie i zapisywanie danych o liczbie kroków.

Aby odczytać rekordy, utwórz ReadRecordsRequest i podaj go podczas wywoływania readRecords.

Poniższy przykład pokazuje, jak odczytać dane o liczbie kroków użytkownika w określonym czasie. Rozszerzony przykład z SensorManager, znajdziesz w przewodniku po danych o liczbie kroków.

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        HeartRateRecord::class,
        timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
    )
)
response.records.forEach { record ->
    /* Process records */
}

Możesz też odczytywać dane w sposób zagregowany za pomocą aggregate.

suspend fun readStepsAggregate(startTime: Instant, endTime: Instant): Long {
    val response = healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
    return response[StepsRecord.COUNT_TOTAL] ?: 0L
}

Odczytywanie kroków na urządzeniu mobilnym

W Androidzie 14 (poziom API 34) i rozszerzeniu SDK w wersji 20 lub nowszej Health Connect umożliwia zliczanie kroków na urządzeniu. Jeśli jakakolwiek aplikacja otrzyma uprawnienie READ_STEPS, Health Connect zacznie rejestrować kroki z urządzenia z Androidem, a użytkownicy będą widzieć dane o krokach automatycznie dodawane do wpisów Kroki w Health Connect.

Aby sprawdzić, czy zliczanie kroków na urządzeniu jest dostępne, upewnij się, że urządzenie ma Androida 14 (poziom API 34) i co najmniej rozszerzenie SDK w wersji 20:

val isStepTrackingAvailable =
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20

Jeśli Twoja aplikacja odczytuje zagregowane liczby kroków za pomocą aggregate i nie filtruje według DataOrigin, kroki na urządzeniu są automatycznie uwzględniane w sumie i nie trzeba wprowadzać żadnych zmian w związku z aktualizacją z czerwca 2026 r.

Zmiana atrybucji kroków na urządzeniu

Od aktualizacji z czerwca 2026 r. kroki śledzone natywnie przez Health Connect są przypisywane do syntetycznej nazwy pakietu (SPN), np. com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

Wcześniej wbudowane kroki były przypisywane do nazwy pakietu android. Dane historyczne o krokach zarejestrowane przed czerwcem 2026 r. zachowują nazwę pakietu android.

SPN są specyficzne dla urządzenia i ograniczone do poszczególnych aplikacji, aby chronić prywatność użytkowników:

  • Stabilne: SPN na bieżącym urządzeniu jest stabilne w przypadku Twojej aplikacji.
  • Ograniczone do aplikacji: różne aplikacje na tym samym urządzeniu widzą różne SPN w przypadku danych o krokach na urządzeniu.

Zapytanie o kroki na urządzeniu

Ponieważ SPN są ograniczone i specyficzne dla urządzenia, nie wolno ich zakodować na stałe. Zamiast tego użyj interfejsu API getCurrentDeviceDataSource(), aby pobrać SPN na bieżącym urządzeniu.

Zliczanie kroków na urządzeniu wymaga rozszerzenia SDK w wersji 20 lub nowszej, ale interfejs API getCurrentDeviceDataSource() jest dostępny w Androidzie 14 (poziom API 34) z rozszerzeniem SDK w wersji 11 lub nowszej.

Interfejs API getCurrentDeviceDataSource() nie jest jeszcze dostępny w bibliotece Jetpack Health Connect. W poniższych przykładach używamy interfejsu API platformy Android:

import android.content.Context
import android.health.connect.HealthConnectManager

val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
val deviceDataSource = healthConnectManager?.getCurrentDeviceDataSource()
val currentDeviceSpn = deviceDataSource?.deviceDataOrigin?.packageName

Jeśli Twoja aplikacja musi odczytywać kroki na urządzeniu lub wyświetla dane o krokach podzielone według aplikacji źródłowej lub urządzenia, musisz wysłać zapytanie o rekordy, w których DataOrigin ma wartość android lub pasuje do SPN urządzenia. Jeśli Twoja aplikacja wyświetla atrybucję danych o krokach, użyj metadata.device aby zidentyfikować urządzenie źródłowe poszczególnych rekordów. W przypadku kroków na urządzeniu zidentyfikowanych przez SPN w zagregowanych danych możesz użyć metadanych urządzenia, takich jak model lub manufacturer, z DeviceDataSource do atrybucji, albo użyć ogólnej etykiety, np. „Twój telefon”, w przypadku kroków na urządzeniu.

Poniższy przykład pokazuje, jak odczytać zagregowane dane o liczbie kroków na urządzeniu, filtrując zarówno według android, jak i SPN bieżącego urządzenia:

import android.content.Context
import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.DataOrigin
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter
import java.time.Instant

suspend fun readDeviceStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    context: Context,
    startTime: Instant,
    endTime: Instant
) {
    // 1. Check if SDK Extension 11+ is available for getCurrentDeviceDataSource()
    val isDataSourceApiAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.U &&
            SdkExtensions.getExtensionVersion(Build.VERSION_CODES.U) >= 11

    try {
        val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)

        // 2. Safely fetch the package name only if API is available and data exists
        val currentDeviceSpn = if (isDataSourceApiAvailable) {
            healthConnectManager?.getCurrentDeviceDataSource()?.deviceDataOrigin?.packageName
        } else {
            null
        }

        val dataOriginFilters = mutableSetOf(DataOrigin("android"))

        // 3. Explicit null-safety check using .let
        currentDeviceSpn?.let {
            dataOriginFilters.add(DataOrigin(it))
        }

        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = dataOriginFilters
            )
        )

        val stepCount = response[StepsRecord.COUNT_TOTAL]

    } catch (e: Exception) {
        // Now this catch block only handles actual runtime exceptions, 
        // rather than Errors from missing methods.
    }
}

Zliczanie kroków na urządzeniu

  • Użycie czujnika: Health Connect korzysta z czujnika TYPE_STEP_COUNTER z SensorManager. Ten czujnik jest zoptymalizowany pod kątem niskiego zużycia energii, dzięki czemu idealnie nadaje się do ciągłego śledzenia kroków w tle.
  • Szczegółowość danych: aby oszczędzać baterię, dane o krokach są zwykle grupowane i zapisywane w bazie danych Health Connect nie częściej niż raz na minutę.
  • Atrybucja: kroki zarejestrowane przez tę funkcję przed czerwcem 2026 r. są przypisywane do nazwy pakietu android w DataOrigin. Po tej dacie są one przypisywane do SPN specyficznego dla urządzenia. Więcej informacji znajdziesz w sekcji Zmiana atrybucji kroków na urządzeniu.
  • Aktywacja: mechanizm zliczania kroków na urządzeniu jest aktywny tylko wtedy, gdy co najmniej 1 aplikacja na urządzeniu ma uprawnienie READ_STEPS w Health Connect.

Przykład odczytywania w tle

Aby odczytywać dane w tle, zadeklaruj to uprawnienie w pliku manifestu:

<application>
  <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
...
</application>

Poniższy przykład pokazuje, jak odczytać dane o liczbie kroków użytkownika w określonym czasie w tle za pomocą WorkManager:

class ScheduleWorker(appContext: Context, workerParams: WorkerParameters) :
    CoroutineWorker(appContext, workerParams) {

    override suspend fun doWork(): Result {
        val healthConnectClient = HealthConnectClient.getOrCreate(applicationContext)
        // Perform background read logic here
        return Result.success()
    }
}
fun enqueueBackgroundReadWorker(context: Context, healthConnectClient: HealthConnectClient) {
    if (healthConnectClient
            .features
            .getFeatureStatus(
                HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
            ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE
    ) {

        val periodicWorkRequest = PeriodicWorkRequestBuilder<ScheduleWorker>(1, TimeUnit.HOURS)
            .build()

        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "read_health_connect",
            ExistingPeriodicWorkPolicy.KEEP,
            periodicWorkRequest
        )
    }
}

Parametr ReadRecordsRequest ma domyślną wartość pageSize równą 1000. Jeśli liczba rekordów w pojedynczej readResponse przekracza pageSize żądania, musisz przejść przez wszystkie strony odpowiedzi, aby pobrać wszystkie rekordy za pomocą pageToken. Uważaj jednak, aby nie przekroczyć limitu liczby żądań.

Przykład odczytywania za pomocą pageToken

Do odczytywania rekordów zalecamy używanie pageToken, aby pobrać wszystkie dostępne dane z żądanego okresu.

Poniższy przykład pokazuje, jak odczytać wszystkie rekordy do wyczerpania wszystkich tokenów strony:

val type = HeartRateRecord::class
val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofDays(7))

try {
    var pageToken: String? = null
    do {
        val readResponse =
            healthConnectClient.readRecords(
                ReadRecordsRequest(
                    recordType = type,
                    timeRangeFilter = TimeRangeFilter.between(
                        startTime,
                        endTime
                    ),
                    pageToken = pageToken
                )
            )
        val records = readResponse.records
        // Do something with records
        pageToken = readResponse.pageToken
    } while (pageToken != null)
} catch (quotaError: IllegalStateException) {
    // Backoff
}
Więcej informacji o sprawdzonych metodach odczytywania dużych zbiorów danych znajdziesz w artykule Planowanie, aby uniknąć ograniczenia liczby żądań.

Odczytywanie wcześniej zapisanych danych

Jeśli aplikacja zapisała wcześniej rekordy w Health Connect, może odczytywać dane historyczne. Dotyczy to sytuacji, w których aplikacja musi ponownie zsynchronizować się z Health Connect po ponownym zainstalowaniu przez użytkownika.

Obowiązują pewne ograniczenia dotyczące odczytu:

  • Android 14 i nowszy

    • Brak limitu historycznego na odczytywanie przez aplikację własnych danych.
    • 30-dniowy limit na odczytywanie przez aplikację innych danych.
  • Android 13 i starszy

    • 30-dniowy limit na odczytywanie przez aplikację dowolnych danych.

Ograniczenia można usunąć, prosząc o uprawnienia do odczytu.

Aby odczytać dane historyczne, musisz wskazać nazwę pakietu jako obiekt DataOrigin w parametrze dataOriginFilter w ReadRecordsRequest.

Poniższy przykład pokazuje, jak wskazać nazwę pakietu podczas odczytywania rekordów tętna:

try {
    val response =  healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = HeartRateRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            dataOriginFilter = setOf(DataOrigin("com.my.package.name"))
        )
    )
    for (record in response.records) {
        // Process each record
    }
} catch (e: Exception) {
    // Run error handling here
}

Odczytywanie danych starszych niż 30 dni

Domyślnie wszystkie aplikacje mogą odczytywać dane z Health Connect przez maksymalnie 30 dni przed pierwszym przyznaniem uprawnień.

Jeśli chcesz rozszerzyć uprawnienia do odczytu poza domyślne ograniczenia, poproś o PERMISSION_READ_HEALTH_DATA_HISTORY. W przeciwnym razie próba odczytania rekordów starszych niż 30 dni bez tego uprawnienia spowoduje błąd.

Historia uprawnień usuniętej aplikacji

Jeśli użytkownik usunie Twoją aplikację, wszystkie uprawnienia, w tym uprawnienia do historii, zostaną cofnięte. Jeśli użytkownik ponownie zainstaluje Twoją aplikację i ponownie przyzna uprawnienia, będą obowiązywać te same domyślne ograniczenia, a Twoja aplikacja będzie mogła odczytywać dane z Health Connect przez maksymalnie 30 dni przed tą nową datą.

Załóżmy na przykład, że użytkownik usunie Twoją aplikację 10 maja 2023 r., a następnie zainstaluje ją ponownie 15 maja 2023 r. i przyzna uprawnienia do odczytu. Najwcześniejsza data, od której Twoja aplikacja może teraz domyślnie odczytywać dane, to 15 kwietnia 2023 r.

Obsługa wyjątków

W przypadku wystąpienia problemu Health Connect zgłasza standardowe wyjątki dotyczące operacji CRUD. Twoja aplikacja powinna odpowiednio przechwytywać i obsługiwać każdy z tych wyjątków.

Każda metoda w HealthConnectClient zawiera listę wyjątków, które mogą zostać zgłoszone. Ogólnie rzecz biorąc, Twoja aplikacja powinna obsługiwać te wyjątki:

Tabela 1. Wyjątki Health Connect i zalecane sprawdzone metody
Wyjątek Opis Zalecana sprawdzona metoda
IllegalStateException Wystąpił jeden z tych scenariuszy:

  • Usługa Health Connect jest niedostępna.
  • Żądanie jest nieprawidłowe. Na przykład żądanie agregacji w okresowych przedziałach czasu, w których do timeRangeFilter używany jest obiekt Instant.

Przed wysłaniem żądania rozwiąż ewentualne problemy z danymi wejściowymi. Najlepiej przypisywać wartości do zmiennych lub używać ich jako parametrów w funkcji niestandardowej zamiast używać ich bezpośrednio w żądaniach, aby można było stosować strategie obsługi błędów.
IOException Podczas odczytywania i zapisywania danych na dysku występują problemy. Aby uniknąć tego problemu, wykonaj te czynności:

  • Utwórz kopię zapasową wszystkich danych wejściowych użytkownika.
  • Zadbaj o to, aby aplikacja mogła obsługiwać wszelkie problemy, które wystąpią podczas operacji zapisu zbiorczego. Na przykład upewnij się, że proces przechodzi do następnego etapu i wykonuje pozostałe operacje.
  • Stosuj strategie ponawiania i wycofywania, aby rozwiązywać problemy z żądaniami.

RemoteException Wystąpiły błędy w usłudze bazowej, z którą łączy się pakiet SDK, lub podczas komunikacji z nią.

Na przykład Twoja aplikacja próbuje usunąć rekord o danym uid. Wyjątek jest jednak zgłaszany po tym, jak aplikacja stwierdzi podczas sprawdzania w usłudze bazowej, że rekord nie istnieje.
Aby uniknąć tego problemu, wykonaj te czynności:

  • Regularnie synchronizuj magazyn danych aplikacji z Health Connect.
  • Stosuj strategie ponawiania i wycofywania, aby rozwiązywać problemy z żądaniami.

SecurityException Występują problemy, gdy żądania wymagają uprawnień, które nie zostały przyznane. Aby tego uniknąć, upewnij się, że w opublikowanej aplikacji zadeklarowano użycie typów danych Health Connect. Musisz też zadeklarować uprawnienia Health Connect w pliku manifestu i w aktywności.