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

Данное руководство совместимо с Health Connect версии 1.1.0-alpha12 .

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

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

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

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

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

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

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

val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = ZoneOffset.UTC,
    endZoneOffset = ZoneOffset.UTC,
    metadata = Metadata.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    )
)

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

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

В этом типе данных все питательные вещества представлены в единицах Mass , а energy представлена ​​в единицах 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.manualEntry(
        device = Device(type = Device.TYPE_PHONE)
    )
)

Записи с данными серий

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

В этом типе данных samples параметров представлены списком выборок Heart Rate . Каждая выборка содержит значение 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.autoRecorded(
        device = Device(type = Device.TYPE_WATCH)
    ))

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

После создания экземпляра клиента ваше приложение должно запросить разрешения у пользователя. Пользователи должны иметь возможность предоставлять или отклонять разрешения в любое время.

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

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(StepsRecord::class),
  HealthPermission.getWritePermission(StepsRecord::class)
)

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

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

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

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

Одним из распространенных рабочих процессов в Health Connect является запись данных. Чтобы добавить записи, используйте insertRecords .

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

suspend fun insertSteps(healthConnectClient: HealthConnectClient) {
    val endTime = Instant.now()
    val startTime = endTime.minus(Duration.ofMinutes(5))
    try {
        val stepsRecord = StepsRecord(
            count = 120,
            startTime = startTime,
            endTime = endTime,
            startZoneOffset = ZoneOffset.UTC,
            endZoneOffset = ZoneOffset.UTC,
            metadata = Metadata.autoRecorded(
                device = Device(type = Device.TYPE_WATCH)
            )
        )
        healthConnectClient.insertRecords(listOf(stepsRecord))
    } catch (e: Exception) {
        // Run error handling here
    }
}

Обновить данные

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

Метаданные

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

Характеристики Описание
id Каждая Record в Health Connect имеет уникальное значение id .
Health Connect автоматически заполняет это поле при добавлении новой записи.
lastModifiedTime Каждая Record также отслеживает время последнего изменения записи.
Health Connect заполняет эту информацию автоматически.
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
    }
}

Вставить через идентификатор записи клиента

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

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

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

suspend fun pullStepsFromDatastore() : 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.autoRecorded(
            clientRecordId = "Your client record ID",
            device = Device(type = Device.TYPE_WATCH)
        ),
        // Assign more parameters for this record
    )
    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())

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

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

Чтобы включить управление версиями в ваши данные, вам необходимо предоставить 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.manualEntry(
        clientRecordId = "Your supplied record ID",
        clientRecordVersion = 0L, // Your supplied record version
        device = Device(type = Device.TYPE_WATCH)
    )
)

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

Лучшие практики записи данных

Приложения должны записывать в Health Connect только данные из собственных источников .

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

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

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

Пассивное отслеживание

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

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

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

    val constraints = Constraints.Builder()
        .requiresBatteryNotLow()
        .requiresDeviceIdle(true)
        .build()
    
    val writeDataWork = PeriodicWorkRequestBuilder<WriteDataToHealthConnectWorker>(
            15,
            TimeUnit.MINUTES,
            5,
            TimeUnit.MINUTES
        )
        .setConstraints(constraints)
        .build()
    

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

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

Убедитесь, что ваше приложение не поддерживает работу Health Connect в течение всего мероприятия.

Данные должны быть записаны в Health Connect одним из двух способов:

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

Лучшие практики для детализации и частоты записей

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

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

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

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

Тип данных

Единица

Ожидал

Пример

Шаги

шаги

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

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 экз./мин.

Толкание инвалидной коляски

толкает

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

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

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

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

АктивныеКалорииСожженные

Калории

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

20:39 - 20:40 - 3.048м

23:23 - 23:24 - 9.144м

ЭтажиПоднялись

полы

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

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

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

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

Частота сердечных сокращений

ударов в минуту

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

6:11:15 утра - 55 ударов в минуту

6:11:30 утра - 56 ударов в минуту

6:11:45 утра - 56 ударов в минуту

6:12:00 утра - 55 ударов в минуту

Изменчивость ЧССRmssd

РС

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

6:11 утра - 23 мс

Частота дыхания

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

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

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

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

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

Насыщение Кислородом

%

Каждый час

6:11 - 95.208%

Писать сеансы

Данные следует записывать в Health Connect по окончании тренировки или сеанса сна.

Лучше всего записывать любой сеанс сна или сеанс упражнений с помощью записывающего устройства и соответствующих метаданных.

Как минимум, ваша заявка должна соответствовать указаниям в столбце «ожидаемое» ниже. По возможности следуйте указаниям «лучшее».

Данные, отслеживаемые во время учений

Тип данных

Единица

Ожидал

Лучший

Пример

Шаги

шаги

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

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

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

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

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

ШагиКаденция

шагов/мин

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

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

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 км

АктивныеКалорииСожженные

Калории

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

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

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 - 3.048м

20:39 - 20:40 - 3.048м

23:23 - 23:24 - 9.144м

УпражненияМаршруты

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

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

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

Частота сердечных сокращений

ударов в минуту

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

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

23:14-23:15 - 150 ударов в минуту

Данные отслеживаются во время сна

Тип данных

Единица

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

Пример

Стадия сна

этап

Детализированный период времени для каждой стадии сна

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

23:50 - 23:56 - легкий сон

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

Частота сердечных сокращений в состоянии покоя

ударов в минуту

Одно дневное значение (ожидается первым делом утром)

6:11 утра - 60 ударов в минуту

Насыщение Кислородом

%

Одно дневное значение (ожидается первым делом утром)

6:11 - 95.208%