Запись данных

Это руководство совместимо с платформой "Здоровье и спорт" версии 1.1.0-alpha12 или более поздней.

В этом руководстве рассказывается, как записывать и обновлять данные в Health Connect.

Обработка нулевых значений

Для некоторых типов данных, таких как шаги, расстояние или калории, может быть указано значение 0. Записывайте нулевые значения, только если пользователь действительно был неактивен, когда носил устройство. Не записывайте нулевые значения, если устройство не использовалось, данные отсутствуют или разрядился аккумулятор. В таких случаях не указывайте запись, чтобы не вводить пользователей в заблуждение.

Настройка структуры данных

Прежде чем записывать данные, нам нужно сначала настроить записи. Для более чем 50 типов данных, каждый из которых имеет свою структуру. Подробную информацию о доступных типах данных можно найти в справочнике по Jetpack.

Основные записи

Тип данных Шаги в сервисе "Здоровье и спорт" позволяет фиксировать количество шагов, сделанных пользователем между измерениями. Количество шагов – это распространенный показатель на платформах, связанных со здоровьем, фитнесом и хорошим самочувствием.

В примере ниже показано, как задать данные о количестве шагов.

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

Записи с единицами измерения

Для точности данных платформа "Здоровье и спорт" может хранить значения вместе с единицами измерения. Например, тип данных Питание содержит множество параметров. В нем есть множество необязательных полей для указания питательных веществ – от общего количества углеводов до витаминов. Каждый элемент данных представляет собой питательные вещества, которые потенциально были потреблены в составе блюда или продукта питания.

В этом типе данных все питательные вещества представлены в единицах массы, а energy – в единицах энергии.

В примере ниже показано, как задать данные о питании для пользователя, который съел банан.

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(1))

val banana = NutritionRecord(
    name = "banana",
    energy = 105.0.kilocalories,
    dietaryFiber = 3.1.grams,
    potassium = 0.422.grams,
    totalCarbohydrate = 27.0.grams,
    totalFat = 0.4.grams,
    saturatedFat = 0.1.grams,
    sodium = 0.001.grams,
    sugar = 14.0.grams,
    vitaminB6 = 0.0005.grams,
    vitaminC = 0.0103.grams,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = ZoneOffset.UTC,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_PHONE)
    )
)

Записи с данными о сериях

Платформа "Здоровье и спорт" может хранить список данных серии. Пример – тип данных Пульс, который фиксирует серию измерений частоты сердечных сокращений между показаниями.

В этом типе данных параметр samples представлен списком образцов пульса. Каждый образец содержит значение beatsPerMinute и значение time.

В примере ниже показано, как задать данные о пульсе.

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(5))

val heartRateRecord = HeartRateRecord(
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    // records 10 arbitrary data, to replace with actual data
    samples = List(10) { index ->
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(index.toLong()),
            beatsPerMinute = 100 + index.toLong(),
        )
    },
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

Запросите разрешения у пользователя

После создания экземпляра клиента приложение должно запросить разрешения у пользователя. У пользователей должна быть возможность в любой момент предоставить или отозвать разрешения. Для этого создайте набор разрешений для нужных типов данных. Убедитесь, что разрешения в наборе сначала объявлены в манифесте Android.

val permissions =
    setOf(
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Используйте getGrantedPermissions, чтобы проверить, есть ли у приложения необходимые разрешения. Если нет, запросите их с помощью createRequestPermissionResultContract. Откроется экран разрешений платформы "Здоровье и спорт".
val permissions = setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class)
    )

val requestPermissionsLauncher = rememberLauncherForActivityResult(
    contract = PermissionController.createRequestPermissionResultContract()
) { grantedPermissions ->
    if (grantedPermissions.containsAll(permissions)) {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") }
    } else {
        coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") }
    }
}
Поскольку пользователи могут предоставлять или отзывать разрешения в любое время, ваше приложение должно проверять разрешения каждый раз перед их использованием и обрабатывать сценарии, в которых разрешение отсутствует.

Запись данных

Один из распространенных рабочих процессов на платформе "Здоровье и спорт" – запись данных. Чтобы добавить записи, нажмите insertRecords.

В примере ниже показано, как записать данные о количестве шагов.

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

Обновление данных

Если вам нужно изменить одну или несколько записей, например при синхронизации хранилища данных приложения с данными платформы "Здоровье и спорт", вы можете обновить данные. Существует два способа обновления существующих данных в зависимости от идентификатора, используемого для поиска записей.

Метаданные

Сначала рассмотрим класс Metadata, который необходим для обновления данных. При создании каждого объекта Record в сервисе "Здоровье и спорт" у него есть поле metadata. С синхронизацией связаны следующие свойства:

Свойства Описание
id У каждого объекта Record в Health Connect есть уникальное значение id.
Приложение "Здоровье и спорт" автоматически заполняет это поле при добавлении новой записи.
lastModifiedTime Каждая Record также отслеживает, когда запись была изменена в последний раз.
Данные заполняются автоматически из приложения "Здоровье и спорт".
clientRecordId Каждому объекту Record можно присвоить уникальный идентификатор, который будет использоваться в качестве ссылки в хранилище данных приложения.
Это значение предоставляет ваше приложение.
clientRecordVersion Если в записи есть clientRecordId, то clientRecordVersion можно использовать, чтобы синхронизировать данные с версией в хранилище данных приложения.
Это значение предоставляет ваше приложение.

Обновление после чтения по диапазону дат

Чтобы обновить данные, сначала подготовьте нужные записи. При необходимости внесите изменения в записи. Затем вызовите updateRecords, чтобы внести изменения.

В примере ниже показано, как обновить данные. Для этого значения смещения часового пояса каждой записи корректируются в соответствии с PST.

suspend fun updateSteps(
    healthConnectClient: HealthConnectClient,
    prevRecordStartTime: Instant,
    prevRecordEndTime: Instant
) {
    try {
        val request = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = StepsRecord::class, timeRangeFilter = TimeRangeFilter.between(
                    prevRecordStartTime,
                    prevRecordEndTime
                )
            )
        )

        val newStepsRecords = arrayListOf<StepsRecord>()
        for (record in request.records) {
            // Adjusted both offset values to reflect changes
            val sr = StepsRecord(
                count = record.count,
                startTime = record.startTime,
                startZoneOffset = record.startTime.atZone(ZoneId.of("PST")).offset,
                endTime = record.endTime,
                endZoneOffset = record.endTime.atZone(ZoneId.of("PST")).offset,
                metadata = record.metadata
            )
            newStepsRecords.add(sr)
        }

        healthConnectClient.updateRecords(newStepsRecords)
    } catch (e: Exception) {
        // Run error handling here
    }
}

Обновление или вставка с помощью идентификатора записи клиента

Если вы используете необязательные значения Client Record ID и Client Record Version, рекомендуем использовать insertRecords вместо updateRecords.

Функция insertRecords позволяет обновлять и вставлять данные. Если в сервисе "Здоровье и спорт" уже есть данные с указанными идентификаторами Client Record ID, они будут перезаписаны. В противном случае они записываются как новые данные. Этот сценарий полезен, когда вам нужно синхронизировать данные из хранилища приложения с платформой "Здоровье и спорт".

В примере ниже показано, как выполнить операцию upsert для данных, извлеченных из хранилища данных приложения.

 fun pullStepsFromDatastore(startTime: Instant, endTime: Instant) : ArrayList<StepsRecord> {
    val appStepsRecords = arrayListOf<StepsRecord>()
    // Pull data from app datastore
    // ...
    // Make changes to data if necessary
    // ...
    // Store data in appStepsRecords
    // ...
    var sr = StepsRecord(
        metadata = Metadata.activelyRecorded(
            clientRecordId = "Your client record ID",
            clientRecordVersion = 0L,
            device = Device(type = Device.TYPE_WATCH)
        ),
        startTime = startTime,
        startZoneOffset = startTime.atZone(ZoneId.of("PST")).offset,
        endTime = endTime,
        endZoneOffset = endTime.atZone(ZoneId.of("PST")).offset,
        count = 120
    )
    appStepsRecords.add(sr)
    // ...
    return appStepsRecords
}

suspend fun upsertSteps(
    healthConnectClient: HealthConnectClient,
    newStepsRecords: ArrayList<StepsRecord>
) {
    try {
        healthConnectClient.insertRecords(newStepsRecords)
    } catch (e: Exception) {
        // Run error handling here
    }
}

После этого вы сможете вызывать эти функции в основном потоке.

upsertSteps(healthConnectClient, pullStepsFromDatastore(
    startTime = startTime,
    endTime = endTime
))

Проверка значения в версии записи клиента

Если процесс обновления данных включает версию записи клиента, платформа "Здоровье и спорт" сравнивает значения clientRecordVersion. Если версия вставляемых данных выше, чем версия существующих, выполняется операция upsert. В противном случае изменение игнорируется и значение остается прежним.

Чтобы включить управление версиями в данные, необходимо предоставить Metadata.clientRecordVersion со значением Long на основе логики управления версиями.

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofMinutes(15))

val stepsRecord = StepsRecord(
    count = 100L,
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.activelyRecorded(
        clientRecordId = "Your supplied record ID",
        clientRecordVersion = 0L, // Your supplied record version
        device = Device(type = Device.TYPE_WATCH)
    )
)

При операциях upsert значение version не увеличивается автоматически при каждом изменении, что предотвращает непреднамеренную перезапись данных. В этом случае вам придется вручную указать более высокое значение.

Общие рекомендации

Приложение должно записывать все поддерживаемые собственные данные. При желании вы можете разрешить приложению записывать данные, полученные из сторонних источников. Однако если ваше приложение прочитало данные из сервиса "Здоровье и спорт", эти данные не должны быть записаны обратно в сервис.

При записи данных, импортированных или полученных из другого источника, вы должны правильно указать их происхождение и метаданные исходного устройства. Для этого необходимо предоставить следующие метаданные для каждой записи:

  • recordingMethod. Для автоматически или вручную записанных данных мы ожидаем, что метод записи будет обновлен, чтобы отразить тип записанной активности:
    • RECORDING_METHOD_AUTOMATICALLY_RECORDED – если данные были записаны автоматически, например фитнес-браслет определил, что пользователь вышел на пробежку.
    • RECORDING_METHOD_ACTIVELY_RECORDED: если пользователь начал новую тренировку, например велосипедную, на носимом устройстве.
    • RECORDING_METHOD_MANUAL_ENTRY – если пользователь ввел данные вручную.
  • device.type – необходимо указать тип устройства из списка поддерживаемых типов Device.
  • device.manufacturer – производитель устройства, например Fitbit.
  • device.model – модель устройства, например "Charge 3".
  • device.udi (необязательный). Идентификатор устройства (DI), который является частью уникального идентификатора медицинского изделия (UDI). Подробную информацию о необходимых разрешениях и правилах конфиденциальности можно найти в руководстве по метаданным.

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

Если данные в вашем приложении были импортированы из другого приложения, то ответственность за запись собственных данных в платформу "Здоровье и спорт" лежит на другом приложении.

Также рекомендуется реализовать логику, которая обрабатывает исключения записи, например, когда данные выходят за пределы допустимого диапазона или возникает внутренняя системная ошибка. Вы можете применить стратегии задержки и повторных попыток в механизме планирования заданий. Если запись в "Здоровье и спорт" не удалась, убедитесь, что ваше приложение может продолжить работу после этой точки экспорта. Не забывайте регистрировать ошибки и сообщать о них, чтобы упростить диагностику.

При отслеживании данных вы можете следовать нескольким рекомендациям в зависимости от того, как ваше приложение записывает данные.

Обработка часовых поясов

При записи данных, связанных со временем, не устанавливайте по умолчанию смещение zoneOffset.UTC, так как это может привести к неточным временным меткам, если пользователи находятся в других часовых поясах. Вместо этого рассчитайте смещение на основе фактического местоположения устройства. Часовой пояс устройства можно получить с помощью ZoneId.systemDefault().

val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofDays(1))
val stepsRecords = mutableListOf<StepsRecord>()
var sampleTime = startTime
val minutesBetweenSamples = 15L
while (sampleTime < endTime) {
    // Get the default ZoneId then convert it to an offset
    val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(sampleTime)
    stepsRecords += StepsRecord(
        startTime = sampleTime.minus(Duration.ofMinutes(minutesBetweenSamples)),
        startZoneOffset = zoneOffset,
        endTime = sampleTime,
        endZoneOffset = zoneOffset,
        count = Random.nextLong(1, 100),
        metadata = Metadata.activelyRecorded(device = Device(type = Device.TYPE_WATCH)),
    )
    sampleTime = sampleTime.plus(Duration.ofMinutes(minutesBetweenSamples))
}
healthConnectClient.insertRecords(
    stepsRecords
)

Подробная информация приведена в документации по ZoneId.

Частота и детализация записи

При записи данных на платформу "Здоровье и спорт" используйте подходящее разрешение. Использование подходящего разрешения помогает снизить нагрузку на хранилище, сохраняя при этом согласованность и точность данных. Разрешение данных включает в себя два аспекта:

  • Частота записи. Как часто приложение записывает новые данные на платформе "Здоровье и спорт".
    • Записывайте данные как можно чаще, когда они доступны, но не забывайте о производительности устройства.
    • Чтобы не снижать время работы от батареи и другие показатели производительности, максимальный интервал между записями должен составлять 15 минут.
  • Детализация записанных данных. Как часто собирались данные.
    • Например, записывайте данные о пульсе каждые 5 секунд.
    • Для разных типов данных требуется разная частота дискретизации. Обновлять данные о количестве шагов каждую секунду не имеет смысла, лучше делать это реже, например каждые 60 секунд.
    • Более высокая частота дискретизации позволяет пользователям получать более подробные данные о здоровье и физической активности. Частота дискретизации должна обеспечивать баланс между детализацией и производительностью.

Дополнительные правила

При записи данных следуйте этим рекомендациям:

  • При каждой синхронизации записывайте только новые данные и данные, которые были изменены с момента последней синхронизации.
  • Разбивайте запросы на запись так, чтобы в каждом из них было не более 1000 записей.
  • Задачи будут выполняться, только когда устройство не используется и у него достаточный уровень заряда батареи.
  • Для фоновых задач используйте WorkManager, чтобы планировать периодические задачи с максимальным периодом времени 15 минут.

В следующем коде используется WorkManager для планирования периодических фоновых задач с максимальным периодом времени 15 минут и гибким интервалом 5 минут. Эта конфигурация задается с помощью класса PeriodicWorkRequest.Builder.

val constraints = Constraints.Builder()
    .requiresBatteryNotLow()
    .requiresDeviceIdle(true)
    .build()

val writeDataWork = PeriodicWorkRequestBuilder<WriteDataToHealthConnectWorker>(
        15,
        TimeUnit.MINUTES,
        5,
        TimeUnit.MINUTES
    )
    .setConstraints(constraints)
    .build()

Активное отслеживание

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

Убедитесь, что приложение не поддерживает работу платформы "Здоровье и спорт" на протяжении всего события.

Данные должны записываться на платформу "Здоровье и спорт" одним из двух способов:

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

Рекомендации по детализации и частоте записи

При записи данных на платформу "Здоровье и спорт" используйте подходящее разрешение. Использование подходящего разрешения помогает снизить нагрузку на хранилище, сохраняя при этом согласованность и точность данных. Разрешение данных включает в себя два аспекта:

  1. Частота записи. Как часто приложение отправляет новые данные в сервис "Здоровье и спорт". Записывайте данные как можно чаще, когда появляются новые данные, не забывая при этом о производительности устройства. Чтобы не снижать время работы от батареи и другие показатели производительности, максимальный интервал между записями должен составлять 15 минут.

  2. Детализация записанных данных – частота выборки данных, которые были переданы. Например, записывайте данные о пульсе каждые 5 секунд. Не для каждого типа данных требуется одинаковая частота дискретизации. Обновлять данные о количестве шагов каждую секунду не имеет смысла. Достаточно делать это раз в минуту. Однако более высокая частота дискретизации может дать пользователям более подробное и детальное представление о данных об их здоровье и физической форме. Частота дискретизации должна обеспечивать баланс между детализацией и производительностью.

Структура записей для данных о сериалах

Для типов данных, которые используют серию выборок, например HeartRateRecord, важно правильно структурировать записи. Вместо того чтобы создавать одну запись на весь день и постоянно ее обновлять, создайте несколько записей поменьше, каждая из которых будет представлять определенный интервал времени.

Например, для данных о пульсе нужно создавать новый объект HeartRateRecord каждую минуту. Каждая запись будет иметь время начала и окончания, охватывающее эту минуту, и будет содержать все выборки частоты пульса, зафиксированные в течение этой минуты.

Во время регулярной синхронизации с платформой "Здоровье и спорт" (например, каждые 15 минут) приложение должно записывать все минутные записи, созданные с момента предыдущей синхронизации. Это позволяет поддерживать размер записей на приемлемом уровне и повышает производительность при обработке данных и выполнении запросов.

В следующем примере показано, как создать объект HeartRateRecord для одной минуты, содержащий несколько выборок:

val startTime = Instant.now().truncatedTo(ChronoUnit.MINUTES)
val endTime = startTime.plus(Duration.ofMinutes(1))

val heartRateRecord = HeartRateRecord(
    startTime = startTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = endTime,
    endZoneOffset = ZoneOffset.UTC,
    // Create a new record every minute, containing a list of samples.
    samples = listOf(
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(15),
            beatsPerMinute = 80,
        ),
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(30),
            beatsPerMinute = 82,
        ),
        HeartRateRecord.Sample(
            time = startTime + Duration.ofSeconds(45),
            beatsPerMinute = 85,
        )
    ),
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

Запись данных, отслеживаемых в течение дня

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

Таблица 1. Рекомендации по записи данных

Тип данных

Единица измерения

Ожидаемая

Пример

Шаги

шаг.

Каждую минуту

23:14–23:15 – 5 шагов

23:16–23:17 – 22 шага

23:17–23:18 – 8 шагов

StepsCadence

шаг/мин

Каждую минуту

23:14–23:15 – 5 шаг/мин

23:16–23:17 – 22 шаг/мин

23:17–23:18 – 8 шаг/мин

количество толчков коляски.

толчки

Каждую минуту

23:14–23:15 – 5 толчков

23:16–23:17 – 22 толчка

23:17–23:18 – 8 толчков

ActiveCaloriesBurned

Калории

Каждые 15 минут

23:15–23:30 – 2 ккал

23:30–23:45 – 25 ккал

23:45–00:00 – 5 ккал.

Общее количество сожженных калорий

Калории

Каждые 15 минут

23:15–23:30 – 16 ккал

23:30–23:45 – 16 ккал

23:45–00:00 – 16 ккал

Расстояние

км/мин

Каждую минуту

23:14–23:15 – 0,008 км

23:16–23:16 – 0,021 км

23:17–23:18 – 0,012 км

ElevationGained

м

Каждую минуту

20:36–20:37 – 3,048 м

20:39–20:40 – 3,048 м

23:23–23:24 – 9,144 м

FloorsClimbed

этажи

Каждую минуту

23:14–23:15 – 5 этажей

23:16 - 23:16 - 22 этажа

23:17–23:18 – 8 этажей

HeartRate

уд/мин

4 раза в минуту

6:11:15 – 55 уд/мин

6:11:30 – 56 уд/мин

6:11:45 – 56 уд/мин

6:12:00 – 55 уд/мин

HeartRateVariabilityRmssd

мс

Каждую минуту

6:11 – 23 мс

RespiratoryRate

вдохов в минуту

Каждую минуту

23:14–23:15 – 60 вдохов в минуту

23:16–23:16 – 62 вдоха в минуту

23:17–23:18 – 64 вдоха в минуту

OxygenSaturation

%

Каждый час

6:11 - 95.208%

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

Убедитесь, что приложение не поддерживает работу платформы "Здоровье и спорт" на протяжении всего события.

Данные должны записываться на платформу "Здоровье и спорт" одним из двух способов:

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

Тренировки и сеансы сна

Как минимум, ваше приложение должно соответствовать требованиям, указанным в столбце Ожидаемое поведение таблицы 2. По возможности следуйте рекомендациям из столбца Лучший вариант.

В таблице ниже показано, как записывать данные во время тренировки.

Таблица 2. Рекомендации по записи данных во время тренировки

Тип данных

Единица измерения

Ожидаемая

С уважением,

Пример

Шаги

шаг.

Каждую минуту

Каждую секунду

23:14–23:15 – 5 шагов

23:16–23:17 – 22 шага

23:17–23:18 – 8 шагов

StepsCadence

шаг/мин

Каждую минуту

Каждую секунду

23:14–23:15 – 35 шаг/мин

23:16–23:17 – 37 шаг/мин

23:17–23:18 – 40 шаг/мин

количество толчков коляски.

толчки

Каждую минуту

Каждую секунду

23:14–23:15 – 5 толчков

23:16–23:17 – 22 толчка

23:17–23:18 – 8 толчков

Частота вращения педалей

об/мин

Каждую минуту

Каждую секунду

23:14–23:15 – 65 об/мин

23:16–23:17 – 70 об/мин

23:17–23:18 – 68 об/мин

Питание

ватты

Каждую минуту

Каждую секунду

23:14–23:15 – 250 Вт

23:16–23:17 – 255 Вт

23:17–23:18 – 245 Вт

Скорость

км/мин

Каждую минуту

Каждую секунду

23:14–23:15 – 0,3 км/мин.

23:16–23:17 – 0,4 км/мин.

23:17–23:18 – 0,4 км/мин.

Расстояние

км/м

Каждую минуту

Каждую секунду

23:14–23:15 – 0,008 км

23:16–23:16 – 0,021 км

23:17–23:18 – 0,012 км

ActiveCaloriesBurned

Калории

Каждую минуту

Каждую секунду

23:14–23:15 – 20 ккал

23:16–23:17 – 20 калорий

23:17–23:18 – 25 ккал

Общее количество сожженных калорий

Калории

Каждую минуту

Каждую секунду

23:14–23:15 – 36 ккал

23:16–23:17 – 36 ккал

23:17–23:18 – 41 ккал

ElevationGained

м

Каждую минуту

Каждую секунду

20:36–20:37 – 3,048 м

20:39–20:40 – 3,048 м

23:23–23:24 – 9,144 м

ExerciseRoutes

широта/долгота/высота

Каждые 3–5 секунд

Каждую секунду

HeartRate

уд/мин

4 раза в минуту

Каждую секунду

23:14–23:15 – 150 уд/мин

В таблице 3 показано, как записывать данные во время или после сеанса сна.

Таблица 3. Рекомендации по записи данных во время или после сеанса сна

Тип данных

Единица измерения

Ожидаемые образцы

Пример

Определение фаз сна

этап

Подробные данные о продолжительности каждой фазы сна

23:46–23:50 – бодрствование

23:50–23:56 – поверхностный сон;

23:56–00:16 – глубокий сон;

Пульс в покое

уд/мин

Одно значение в день (желательно утром).

6:11 – 60 уд/мин

OxygenSaturation

%

Одно значение в день (желательно утром)

6:11 - 95.208%

Многоборье

Этот подход использует существующие типы и структуры данных и проверяет совместимость с текущими реализациями платформы "Здоровье и спорт" и средствами чтения данных. Это распространенный подход, используемый фитнес-платформами.

Кроме того, отдельные занятия, такие как плавание, езда на велосипеде и бег, не связаны между собой в Здоровье и спорте, и читатели данных должны выводить взаимосвязь между этими занятиями на основе их временной близости. Переходы между сегментами, например от плавания к езде на велосипеде, не представлены явным образом.

В примере ниже показано, как записать данные о триатлоне.

val swimStartTime = Instant.parse("2024-08-22T08:00:00Z")
val swimEndTime = Instant.parse("2024-08-22T08:30:00Z")
val bikeStartTime = Instant.parse("2024-08-22T08:40:00Z")
val bikeEndTime = Instant.parse("2024-08-22T09:40:00Z")
val runStartTime = Instant.parse("2024-08-22T09:50:00Z")
val runEndTime = Instant.parse("2024-08-22T10:20:00Z")

val swimSession = ExerciseSessionRecord(
    startTime = swimStartTime,
    endTime = swimEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_SWIMMING_OPEN_WATER,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

val bikeSession = ExerciseSessionRecord(
    startTime = bikeStartTime,
    endTime = bikeEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

val runSession = ExerciseSessionRecord(
    startTime = runStartTime,
    endTime = runEndTime,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    metadata = Metadata.activelyRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ),
    startZoneOffset = null,
    endZoneOffset = null,
)

healthConnectClient.insertRecords(listOf(swimSession, bikeSession, runSession))

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

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

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

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

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

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

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

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

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

  • Регулярно синхронизируйте хранилище данных приложения с платформой "Здоровье и спорт".
  • Используйте повторные попытки и стратегии отсрочки для обработки проблем с запросами.

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