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

Это руководство совместимо с версией 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.") }
    }
}
Поскольку пользователи могут в любой момент предоставить или отозвать разрешения, ваше приложение должно проверять их каждый раз перед использованием и обрабатывать ситуации, когда разрешение теряется.

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

Одна из распространенных задач в Health Connect – запись данных. Чтобы добавить записи, используйте приложение "Диктофон" 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, чтобы внести изменения.

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

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

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

Если вы используете необязательные значения "Идентификатор записи клиента" и "Версия записи клиента", рекомендуем использовать insertRecords вместо updateRecords.

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

В примере ниже показано, как выполнить операцию 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) медицинского изделия. Подробную информацию о необходимых разрешениях и правилах конфиденциальности можно найти в руководстве по метаданным.

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

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

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

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

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

При записи данных, связанных со временем, не устанавливайте смещения по умолчанию на 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.

Записывать частоту и детализацию

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

  • Частота записи. Как часто ваше приложение записывает новые данные в Health Connect.
    • Записывайте данные как можно чаще, когда они становятся доступны, но не забывайте о производительности устройства.
    • Чтобы не снижать время работы от батареи и другие показатели производительности, максимальный интервал между записями должен составлять 15 минут.
  • Уровень детализации записанных данных. Как часто выполнялась выборка данных.
    • Например, записывать данные о пульсе каждые пять секунд.
    • Для разных типов данных требуется разная частота выборки. Нет смысла обновлять данные о количестве шагов каждую секунду, поскольку это не дает значительных преимуществ по сравнению с менее частым обновлением, например каждые 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 секунд. Для разных типов данных требуется разная частота выборки. Нет смысла обновлять данные о количестве шагов каждую секунду, поскольку это не дает никаких преимуществ по сравнению с менее частым обновлением, например раз в 60 секунд. Однако более высокая частота выборки может дать пользователям более подробное представление о данных о здоровье и фитнесе. Частота выборки должна быть сбалансирована между детализацией и производительностью.

Как структурировать записи для данных о сериалах

Для типов данных, которые используют серию образцов, например 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 push-уведомлений

Калории, сожженные во время активности

Калории

Каждые 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 км

Набор высоты

м

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

20:36–20:37 – 3048 м

20:39–20:40 – 3048 м

23:23 - 23:24 - 9144 м

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%

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

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

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

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

тренировки и сеансы сна;

Ваше приложение должно соответствовать требованиям, указанным в столбце Expected таблицы 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 push-уведомлений

CyclingPedalingCadence

об/мин

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

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

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 km/min

Расстояние

км/м

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

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

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

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

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

Калории, сожженные во время активности

Калории

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

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

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 калория

Набор высоты

м

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

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

20:36–20:37 – 3048 м

20:39–20:40 – 3048 м

23:23 - 23:24 - 9144 м

ExerciseRoutes

lat/lng/alt

Каждые 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 Проблемы возникают, когда для запросов требуются разрешения, которые не были предоставлены. Чтобы этого не произошло, убедитесь, что вы задекларировали использование типов данных платформы "Здоровье и спорт" для опубликованного приложения. Кроме того, вы должны задекларировать разрешения платформы "Здоровье и спорт" в файле манифеста и в действии.