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 pamięci, gdy są one na pierwszym planie i w tle:

  • Odczytywanie na pierwszym planie: dane z Health Connect możesz zwykle odczytywać, gdy aplikacja jest na pierwszym planie. W takich przypadkach możesz użyć usługi na pierwszym planie, aby wykonać tę operację, jeśli użytkownik lub system umieści aplikację w tle podczas operacji odczytu.

  • Odczytywanie w tle: prosząc użytkownika o dodatkowe uprawnienia, możesz odczytywać dane po tym, jak użytkownik lub system umieści Twoją aplikację w tle. Zobacz pełny przykład odczytu w tle.

Typ danych Kroki w Health Connect rejestruje liczbę kroków, które użytkownik wykonał między odczytami. Liczba kroków to powszechny pomiar na platformach związanych ze zdrowiem, aktywnością fizyczną i dobrym samopoczuciem. Health Connect ułatwia odczytywanie i zapisywanie danych o liczbie kroków.

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

Przykład poniżej pokazuje, jak odczytać dane o liczbie kroków użytkownika w określonym czasie. Rozszerzony przykład z SensorManager znajdziesz w przewodniku po danych dotyczących liczby kroków.

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.readRecords(
            ReadRecordsRequest(
                StepsRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        for (record in response.records) {
            // Process each record
        }
    } catch (e: Exception) {
        // Run error handling here
    }
}

Możesz też odczytywać dane w formie zbiorczej za pomocą aggregate.

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

Przykład odczytywania w tle

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

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

Przykład poniżej pokazuje, jak odczytać dane o liczbie kroków w tle dla użytkownika w określonym czasie za pomocą funkcji WorkManager:

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

    override suspend fun doWork(): Result {
        // Read data and process it.
        ...

        // Return success indicating successful data retrieval
        return Result.success()
    }
}

if (healthConnectClient
    .features
    .getFeatureStatus(
    HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
    ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {

    // Check if necessary permission is granted
    val grantedPermissions = healthConnectClient.permissionController.getGrantedPermissions()

    if (PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND !in grantedPermissions) {
        // Perform read in foreground
        ...
    } else {
        // Schedule the periodic work request in background
        val periodicWorkRequest = PeriodicWorkRequestBuilder<ScheduleWorker>(1, TimeUnit.HOURS)
            .build()

        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "read_health_connect",
            ExistingPeriodicWorkPolicy.KEEP,
            periodicWorkRequest
        )
    }
} else {
  // Background reading is not available, perform read in foreground
  ...
}

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

Przykład odczytu pageToken

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

Poniższy przykład pokazuje, jak odczytać wszystkie rekordy, dopóki nie zostaną wykorzystane wszystkie tokeny 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
}

Informacje 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 zapisywał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 lub nowszy

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

    • 30-dniowy limit odczytywania danych przez aplikację.

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

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

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

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 z okresu do 30 dni przed przyznaniem im uprawnień.

Jeśli musisz rozszerzyć uprawnienia do odczytu poza domyślne ograniczenia, poproś o to, wysyłając 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 aplikację i ponownie przyzna jej uprawnienia, będą obowiązywać te same domyślne ograniczenia, a aplikacja będzie mogła odczytywać dane z Health Connect z okresu do 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 jej uprawnienia do odczytu. Najwcześniejsza data, od której Twoja aplikacja może 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. Aplikacja powinna przechwytywać i obsługiwać każdy z tych wyjątków w odpowiedni sposób.

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

Tabela 1. Wyjątki dotyczące 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 ma nieprawidłową konstrukcję. Na przykład żądanie zbiorcze w okresowych przedziałach, w którym obiekt Instant jest używany w przypadku timeRangeFilter.

Przed wysłaniem żądania najpierw 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 Występują problemy z odczytywaniem i zapisywaniem danych na dysku. Aby uniknąć tego problemu, wykonaj te czynności:

  • Twórz kopie zapasowe wszystkich danych wprowadzonych przez użytkownika.
  • Musi być w stanie poradzić sobie z wszelkimi problemami, które wystąpią podczas operacji zapisu zbiorczego. Na przykład upewnij się, że proces przechodzi dalej i wykonaj pozostałe operacje.
  • Stosuj ponowne próby i strategie 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 aplikacja próbuje usunąć rekord o danym uid. Wyjątek jest jednak zgłaszany po tym, jak aplikacja sprawdzi w usłudze bazowej, że rekord nie istnieje.
Aby uniknąć tego problemu, wykonaj te czynności:

  • Regularnie synchronizuj dane między bazą danych aplikacji a Health Connect.
  • Stosuj ponowne próby i strategie wycofywania, aby rozwiązywać problemy z żądaniami.

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