Улучшите качество сна с помощью Health Connect.

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

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

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

Обзор: Создание комплексного трекера сна

Для создания комплексной системы отслеживания сна с помощью Health Connect выполните следующие основные шаги:

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

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

Прежде чем начать

Перед внедрением функций, отвечающих за сон:

Ключевые понятия

Health Connect представляет данные о сне с помощью нескольких основных компонентов. SleepSessionRecord служит центральной записью данных о сне, содержащей такие сведения, как время начала и окончания, а также стадии сна. Во время сеанса могут записываться различные типы данных, такие как HeartRateRecord или OxygenSaturationRecord .

Сеансы сна

Данные о сне представлены объектом SleepSessionRecord . Каждая запись содержит:

  • startTime
  • endTime
  • stages : Список стадий сна, содержащих данные из файла SleepSessionRecord.Stage , включая глубокий, поверхностный, REM-сон и фазу бодрствования.
  • Дополнительные метаданные сессии (заголовок, примечания)

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

Типы данных

К распространенным типам данных, записываемых во время сеанса сна, относятся:

  • SleepSessionRecord : Записывает продолжительность и стадии сна, включая глубокий, поверхностный, REM-сон и фазу бодрствования.
  • HeartRateRecord : Записывает частоту сердечных сокращений во время сна.
  • OxygenSaturationRecord : Записывает уровень насыщения крови кислородом (SpO2) во время сна.
  • RespiratoryRateRecord : Записывает частоту дыхания во время сна.

Каждый тип данных хранится в виде отдельной записи.

Вопросы развития

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

Фоновое выполнение

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

  • Сервисы переднего плана для сбора данных
  • WorkManager для отложенной записи или синхронизации
  • Стратегии пакетной обработки для регулярной записи детализированных данных, таких как частота сердечных сокращений.

Обеспечьте непрерывность, сохраняя идентификатор сессии неизменным при всех операциях записи.

Разрешения

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

Доступ к сну защищен следующими разрешениями:

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

Чтобы добавить в ваше приложение функцию отслеживания сна, для начала запросите разрешения на использование типа данных SleepSession .

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

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

Для чтения данных о сне необходимо запросить следующие разрешения:

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

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

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

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

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(SleepSessionRecord::class),
  HealthPermission.getWritePermission(SleepSessionRecord::class),
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(OxygenSaturationRecord::class),
  HealthPermission.getWritePermission(OxygenSaturationRecord::class),
  HealthPermission.getReadPermission(RespiratoryRateRecord::class),
  HealthPermission.getWritePermission(RespiratoryRateRecord::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)
  }
}

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

Внедрить сеанс сна

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

Чтобы сопоставить такие типы данных, как HeartRateRecord или OxygenSaturationRecord , с сеансом сна, запишите их с метками времени, которые находятся между startTime и endTime сеанса. Health Connect не использует идентификатор сеанса для связи сеансов сна с подробными данными. Вместо этого связь устанавливается неявно через перекрывающиеся временные интервалы. При чтении данных о сне вы можете использовать временной диапазон сеанса для запроса связанных типов данных, как показано в разделе «Чтение данных о сне» .

Напишите сессию

Хотя такие подробные данные, как частота сердечных сокращений, могут записываться на протяжении всего сеанса сна, сам объект SleepSessionRecord должен быть записан в Health Connect только после завершения сеанса, например, когда пользователь просыпается. Запись должна включать startTime сеанса (startTime), endTime ) и список объектов SleepSessionRecord.Stage , записанных во время сеанса, поскольку SleepSessionRecord требует, чтобы endTime был после startTime .

Чтобы написать запись о сеансе сна:

  1. Сгенерируйте уникальный идентификатор записи клиента.
  2. Когда пользователь просыпается или отслеживание сна прекращается, соберите все стадии сна и создайте запись SleepSessionRecord .
  3. Вставьте запись, используя insertRecords .

Пример:

val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)

val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(3600),
    endTime = sessionStartTime.plusSeconds(7200),
    stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(7200),
    endTime = sessionStartTime.plusSeconds(10800),
    stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages

val session = SleepSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    stages = stages,
    metadata = Metadata(clientRecordId = clientRecordId)
)

healthConnectClient.insertRecords(listOf(session))

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

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

Прочтение сессии с соответствующими данными.

Вы можете читать данные о сеансах сна, используя запрос ReadRecordsRequest с типом записи SleepSessionRecord , отфильтрованный по временному диапазону. Чтобы прочитать связанные данные для данного сеанса, выполните второй запрос для выбранного типа данных, например HeartRateRecord , отфильтровав данные по startTime и endTime сеанса сна.

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

suspend fun readSleepSessionsWithAssociatedData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (sleepRecord in response.records) {
        // Process each session
        val stages = sleepRecord.stages
        val notes = sleepRecord.notes

        // To read specific granular data (like heart rate) that occurred during
        // this session, use the session's startTime and endTime to filter
        // the request for that data type.
        val hrResponse = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(
                    sleepRecord.startTime,
                    sleepRecord.endTime
                )
            )
        )
        for (heartRateRecord in hrResponse.records) {
            for (sample in heartRateRecord.samples) {
                val bpm = sample.beatsPerMinute
            }
        }
    }
}

Передовые методы

Следуйте этим рекомендациям, чтобы повысить достоверность данных и удобство использования:

  • Частота записи
    • Активное отслеживание (в фоновом режиме): Для активного отслеживания сна данные записываются по мере их поступления или с максимальным интервалом в 15 минут.
    • Фоновая синхронизация: используйте WorkManager для отложенной записи. Старайтесь устанавливать интервал в 15 минут, чтобы найти баланс между передачей данных в реальном времени и экономией заряда батареи.
    • Пакетная обработка: Не записывайте каждое событие с датчика по отдельности. Разделите запросы на части. Health Connect обрабатывает до 1000 записей за один запрос на запись.
  • Сохраняйте стабильность и уникальность идентификаторов сессий: используйте согласованные идентификаторы для ваших сессий. Если сессия редактируется или обновляется, использование того же идентификатора предотвратит ее обработку как новой, отдельной сессии сна.
  • Используйте пакетную обработку для различных типов данных: чтобы уменьшить накладные расходы на ввод/вывод и продлить срок службы батареи, группируйте точки данных в один вызов insertRecords а не записывайте каждую точку по отдельности.
  • Избегайте записи дублирующихся данных: используйте идентификаторы клиентов. При создании записей задайте параметр metadata.clientRecordId . Health Connect использует его для идентификации уникальных записей. Если вы попытаетесь записать запись с уже существующим clientRecordId , Health Connect проигнорирует дубликат или обновит существующую запись, а не создаст новую. Установка параметра metadata.clientRecordId — наиболее эффективный способ предотвратить дубликаты при повторных попытках синхронизации или переустановке приложения.

    val record = RespiratoryRateRecord(
        rate = 16.0,
        time = time,
        zoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "respiratory_rate_20231030_1"
        )
    )
    
  • Проверьте существующие данные: перед синхронизацией запросите временной диапазон, чтобы узнать, существуют ли уже записи из вашего приложения.

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

  • Четко обоснуйте необходимость предоставления разрешения: используйте поток Permission.createIntent , чтобы объяснить, почему вашему приложению необходим доступ к данным о здоровье, например: «Для анализа ваших моделей сна».

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

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

Тестирование

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

инструменты проверки

  • Health Connect Toolbox : Используйте это сопутствующее приложение для ручной проверки записей, удаления тестовых данных и имитации изменений в базе данных. Это лучший способ убедиться в правильности хранения ваших записей.
  • Модульное тестирование с помощью FakeHealthConnectClient : используйте библиотеку тестирования, чтобы проверить, как ваше приложение обрабатывает граничные случаи, такие как отзыв разрешений или исключения API, без необходимости использования физического устройства.

Контрольный список качества

Типичная архитектура

Обычно в систему отслеживания сна входят следующие компоненты:

Компонент Управляет
контроллер сессии состояние сессии
Таймер
Логика пакетной обработки
Контроллеры типов данных
Сбор данных
Уровень репозитория (обертывает операции Health Connect): Вставить сессию
Вставьте типы данных
Вставляет стадии сна
Ознакомьтесь с краткими обзорами сессий.
Слой пользовательского интерфейса (дисплеи): Продолжительность
Типы данных в реальном времени
Визуализация стадий сна

Поиск неисправностей

Симптом Возможная причина Разрешение
Отсутствующие типы данных (например, частота сердечных сокращений) Отсутствуют права на запись или некорректно работают временные фильтры. Убедитесь, что вы запросили разрешение на доступ к данным определенного типа, и пользователь его предоставил. Проверьте, что ваш ReadRecordsRequest использует TimeRangeFilter , соответствующий сессии. См. раздел «Разрешения» .
Сессия не записывается Перекрывающиеся временные метки. Приложение Health Connect может отклонять записи, которые частично совпадают с существующими данными из того же приложения. Убедитесь, что время startTime новой сессии позже времени endTime предыдущей.
Данные с датчиков во время сна не регистрировались. Работа основной службы была прекращена или приостановлена. Для сбора данных с датчиков в течение ночи при выключенном экране можно использовать службу переднего плана с foregroundServiceType="health" .
Появляются повторяющиеся записи. Отсутствует clientRecordId . Присвойте каждой записи уникальный clientRecordId в Metadata . Это позволит Health Connect выполнить дедупликацию, если одни и те же данные будут записаны дважды во время повторной попытки синхронизации. См. раздел «Рекомендации» .

Типичные шаги отладки

Проверьте состояние прав доступа. Перед выполнением операции чтения или записи всегда вызывайте getPermissionStatus() . Пользователи могут в любой момент отозвать разрешения в системных настройках.
Проверьте режим выполнения. Если ваше приложение не собирает данные в фоновом режиме, убедитесь, что вы указали правильные разрешения в файле AndroidManifest.xml и что пользователь не перевел приложение в режим "Ограничение использования батареи".