Чтение необработанных данных

В следующем примере показано, как читать необработанные данные в рамках общего рабочего процесса.

Чтение данных

Health Connect позволяет приложениям считывать данные из хранилища данных, когда приложение находится на переднем плане и в фоновом режиме:

  • Чтение в фоновом режиме : обычно вы можете считывать данные из Health Connect, когда ваше приложение находится в фоновом режиме. В таких случаях вы можете использовать службу переднего плана для выполнения этой операции на случай, если пользователь или система переведут ваше приложение в фоновый режим во время операции чтения.

  • Фоновое чтение : запросив у пользователя дополнительное разрешение, вы сможете читать данные после того, как пользователь или система переведут ваше приложение в фоновый режим. См. полный пример фонового чтения .

Тип данных «Шаги» в Health Connect фиксирует количество шагов, пройденных пользователем между измерениями. Количество шагов — это распространённый показатель на платформах для здоровья, фитнеса и оздоровления. Health Connect упрощает чтение и запись данных о количестве шагов.

Чтобы прочитать записи, создайте ReadRecordsRequest и предоставьте его при вызове readRecords .

В следующем примере показано, как считывать данные о количестве шагов пользователя за определённый период времени. Подробный пример использования SensorManager см. в руководстве по данным о количестве шагов .

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
    }
}

Вы также можете прочитать свои данные в агрегированном виде, используя 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
    }
}

Пример фонового чтения

Чтобы читать данные в фоновом режиме, объявите следующее разрешение в файле манифеста:

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

В следующем примере показано, как считывать данные о количестве шагов в фоновом режиме для пользователя за определенное время с помощью 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
  ...
}

Параметр ReadRecordsRequest имеет значение pageSize по умолчанию, равное 1000. Если количество записей в одном readResponse превышает pageSize запроса, необходимо перебрать все страницы ответа, чтобы получить все записи с помощью pageToken . Однако будьте осторожны, чтобы избежать ограничений скорости.

пример чтения pageToken

Рекомендуется использовать pageToken для чтения записей, чтобы получить все доступные данные за запрошенный период времени.

В следующем примере показано, как читать все записи до тех пор, пока не будут исчерпаны все токены страницы:

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
}

Информацию о передовых методах чтения больших наборов данных см. в разделе Планирование действий для избежания ограничения скорости .

Прочитать ранее записанные данные

Если приложение ранее сохраняло данные в Health Connect, оно может прочитать исторические данные. Это применимо в ситуациях, когда приложению требуется повторная синхронизация с Health Connect после его переустановки пользователем.

Действуют некоторые ограничения на чтение:

  • Для Android 14 и выше

    • Отсутствие исторических ограничений на чтение приложением своих собственных данных.
    • 30-дневный лимит на чтение других данных приложением.
  • Для Android 13 и ниже

    • 30-дневный лимит на чтение любых данных приложением.

Ограничения можно снять, запросив разрешение на чтение .

Чтобы прочитать исторические данные, вам необходимо указать имя пакета как объект DataOrigin в параметре dataOriginFilter вашего ReadRecordsRequest .

В следующем примере показано, как указать имя пакета при чтении записей сердечного ритма:

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
}

Чтение данных старше 30 дней

По умолчанию все приложения могут считывать данные из Health Connect за период до 30 дней до момента первого предоставления какого-либо разрешения.

Если вам необходимо расширить разрешения на чтение за пределы ограничений по умолчанию , запросите разрешение PERMISSION_READ_HEALTH_DATA_HISTORY . В противном случае, без этого разрешения, попытка чтения записей старше 30 дней приведёт к ошибке.

История разрешений для удаленного приложения

Если пользователь удалит ваше приложение, все разрешения, включая разрешение на просмотр истории, будут отозваны. Если пользователь переустановит ваше приложение и снова предоставит разрешение, будут применены те же ограничения по умолчанию , и ваше приложение сможет считывать данные из Health Connect за период до 30 дней до этой новой даты.

Например, предположим, что пользователь удалил ваше приложение 10 мая 2023 года, а затем переустановил его 15 мая 2023 года и предоставил разрешения на чтение. Самая ранняя дата, с которой ваше приложение теперь по умолчанию может читать данные, — 15 апреля 2023 года .

Обработка исключений

Health Connect генерирует стандартные исключения для CRUD-операций при возникновении проблем. Ваше приложение должно перехватывать и обрабатывать каждое из этих исключений соответствующим образом.

Каждый метод HealthConnectClient перечисляет возможные исключения. В общем случае ваше приложение должно обрабатывать следующие исключения:

Таблица 1: Исключения Health Connect и рекомендуемые практики
Исключение Описание Рекомендуемая лучшая практика
IllegalStateException Произошел один из следующих сценариев:

  • Услуга Health Connect недоступна.
  • Запрос не является допустимой конструкцией. Например, агрегированный запрос в периодических сегментах, где для timeRangeFilter используется объект Instant .

Прежде чем выполнять запрос, обработайте возможные проблемы с входными данными. Рекомендуется присваивать значения переменным или использовать их в качестве параметров в пользовательской функции, а не использовать их напрямую в запросах, чтобы можно было применять стратегии обработки ошибок.
IOException Возникают проблемы при чтении и записи данных с диска. Чтобы избежать этой проблемы, вот несколько советов:

  • Создавайте резервные копии любых пользовательских данных.
  • Уметь решать любые проблемы, возникающие во время операций массовой записи. Например, убедиться, что процесс завершается после возникновения проблемы и выполняются оставшиеся операции.
  • Применяйте стратегии повторных попыток и отсрочек для решения проблем с запросами.

RemoteException Произошли ошибки в базовой службе, к которой подключается SDK, или при взаимодействии с ней.

Например, ваше приложение пытается удалить запись с заданным uid . Однако исключение возникает после того, как приложение обнаруживает при проверке базовой службы, что запись не существует.
Чтобы избежать этой проблемы, вот несколько советов:

  • Регулярно выполняйте синхронизацию между хранилищем данных вашего приложения и Health Connect.
  • Применяйте стратегии повторных попыток и отсрочек для решения проблем с запросами.

SecurityException Возникают проблемы, когда запросы требуют разрешений, которые не предоставлены. Чтобы избежать этого, убедитесь, что вы указали использование типов данных Health Connect для опубликованного приложения. Кроме того, необходимо указать разрешения Health Connect в файле манифеста и в вашей активности .