Cómo escribir datos

Esta guía es compatible con la versión 1.1.0-alpha12 o posterior de Health Connect.

En esta guía, se explica el proceso de escritura o actualización de datos de Health Connect.

Cómo controlar los valores de cero

Algunos tipos de datos, como los pasos, la distancia o las calorías, pueden tener un valor de 0. Solo escribe valores de cero cuando reflejen una inactividad real mientras el usuario usaba el dispositivo. No escribas valores de cero si no se usó el dispositivo, si faltan datos o si se agotó la batería. En esos casos, omite el registro para evitar datos engañosos.

Cómo configurar la estructura de los datos

Antes de escribir los datos, primero debemos configurar los registros. Para más de 50 tipos de datos, cada uno tiene sus respectivas estructuras. Consulta la referencia de Jetpack para obtener más detalles sobre los tipos de datos disponibles.

Registros básicos

El tipo de datos de Pasos de Health Connect captura la cantidad de pasos que dio un usuario entre cada medición. El recuento de pasos representa una medición común en todas las plataformas de salud, actividad física y bienestar.

En el siguiente ejemplo, se muestra cómo configurar los datos del recuento de pasos:

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

Registros con unidades de medida

Health Connect puede almacenar valores junto con sus unidades de medida para proporcionar una mayor precisión. Un ejemplo es el tipo de datos de Nutrición que es amplio y extenso. Incluye una gran variedad de campos nutricionales opcionales, que van desde carbohidratos totales hasta vitaminas. Cada dato representa los nutrientes que posiblemente se consumieron como parte de una comida o un alimento.

En este tipo de datos, todos los nutrientes se representan en unidades de Masa, mientras que energy se representa en una unidad de Energía.

En el siguiente ejemplo, se muestra cómo configurar los datos de nutrición de un usuario que comió una banana:

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

Registros con datos de series

Health Connect puede almacenar una lista de datos de series. Un ejemplo es el tipo de datos de Frecuencia cardíaca que captura una serie de muestras de latidos detectadas entre lecturas.

En este tipo de datos, el parámetro samples se representa con una lista de muestras de frecuencia cardíaca. Cada muestra contiene un valor beatsPerMinute y un valor time.

En el siguiente ejemplo, se muestra cómo configurar los datos de series de frecuencia cardíaca:

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

Solicita permisos al usuario

Después de crear una instancia de cliente, tu app debe solicitarle permisos al usuario. Los usuarios deben poder otorgar o rechazar permisos en cualquier momento. Para hacerlo, crea un conjunto de permisos para los tipos de datos necesarios. Primero, asegúrate de que los permisos del conjunto se declaren en tu manifiesto de Android.

val permissions =
    setOf(
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Usa getGrantedPermissions para ver si tu app ya tiene otorgados los permisos necesarios. De lo contrario, usa createRequestPermissionResultContract para solicitarlos. Se mostrará la pantalla de permisos de Health Connect.
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.") }
    }
}
Debido a que los usuarios pueden otorgar o revocar permisos en cualquier momento, tu app debe verificar los permisos cada vez que los use y controlar las situaciones en las que se pierda el permiso.

Escribe datos

Uno de los flujos de trabajo comunes de Health Connect es la escritura de datos. Para agregar registros, usa insertRecords.

En el siguiente ejemplo, se muestra cómo escribir datos mediante la inserción de recuentos de pasos:

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

Cómo actualizar datos

Si necesitas cambiar uno o más registros, en especial cuando necesitas sincronizar el almacén de datos de tu app con datos de Health Connect, puedes actualizar los datos. Existen dos maneras de actualizar los datos existentes, que dependen del identificador que se use para encontrar los registros.

Metadatos

Vale la pena examinar la clase Metadata primero, ya que es necesario cuando se actualizan datos. Durante la creación, cada Record de Health Connect tiene un campo metadata. Las siguientes propiedades son relevantes para la sincronización:

Propiedades Descripción
id Cada Record de Health Connect tiene un valor id único.
Health Connect lo propaga automáticamente cuando insertas un registro nuevo.
lastModifiedTime Cada Record también registra la última vez que se modificó el registro.
Health Connect lo propaga automáticamente.
clientRecordId Cada Record puede tener un ID único asociado para usarlo como referencia en el almacén de datos de tu app.
Tu app proporciona este valor.
clientRecordVersion Cuando un registro tiene clientRecordId, se puede usar clientRecordVersion para permitir que los datos permanezcan sincronizados con la versión del almacén de datos de tu app.
Tu app proporciona este valor.

Actualiza después de leer por período

Para actualizar los datos, primero prepara los registros que requieres. Si es necesario, realiza cambios en los registros. Luego, llama a updateRecords para realizar los cambios.

En el siguiente ejemplo, se muestra cómo actualizar los datos. Para este propósito, cada registro tiene sus valores de desplazamiento de zona ajustados en 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
    }
}

Cómo insertar y actualizar mediante el ID de registro del cliente

Si usas los valores opcionales de ID de registro del cliente y de versión del registro del cliente, te recomendamos que uses insertRecords en lugar de updateRecords.

La función insertRecords tiene la capacidad de insertar y actualizar datos. Si los datos existen en Health Connect según el conjunto determinado de IDs de registro del cliente, se reemplazan. De lo contrario, se escriben como datos nuevos. Esta situación es útil cuando necesitas sincronizar los datos del almacén de datos de tu app con Health Connect.

En el siguiente ejemplo, se muestra cómo realizar una inserción y actualización de los datos que se extraen del almacén de datos de la app:

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

Después de eso, podrás llamar a estas funciones en tu subproceso principal.

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

Verificación de valores en la versión de registro del cliente

Si tu proceso de inserción y actualización de datos incluye la versión de registro del cliente, Health Connect realiza verificaciones de comparación en los valores de clientRecordVersion. Si la versión de los datos insertados es superior a la versión de los datos existentes, se produce la inserción y la actualización. De lo contrario, el proceso ignorará el cambio y el valor seguirá siendo el mismo.

Para incluir el control de versiones en tus datos, debes proporcionar a Metadata.clientRecordVersion un valor Long basado en tu lógica de control de versiones.

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

Las inserciones y las actualizaciones no aumentan automáticamente version, lo que evita cualquier instancia inesperada de reemplazo de datos. De esta manera, debes proporcionarle manualmente un valor más alto.

Guía general

Tu app debería escribir todos los datos propios compatibles. De manera opcional, puedes elegir que tu app escriba datos obtenidos de fuentes de terceros. Sin embargo, si tu app leyó datos de Health Connect, esos datos no se deben volver a escribir en Health Connect.

Cuando escribas datos que se hayan importado o derivado de otra fuente, se espera que atribuyas correctamente su origen y los metadatos del dispositivo de origen. Para ello, debes proporcionar los siguientes metadatos para cada registro escrito:

  • recordingMethod: Para los datos registrados automáticamente o manualmente, esperamos que el método de registro se actualice para reflejar el tipo de actividad que se ha registrado:
    • RECORDING_METHOD_AUTOMATICALLY_RECORDED: Si los datos se registraron automáticamente, por ejemplo, una pulsera de fitness detectó automáticamente que el usuario salió a correr.
    • RECORDING_METHOD_ACTIVELY_RECORDED: Si el usuario inició una actividad nueva, como andar en bicicleta, en su wearable.
    • RECORDING_METHOD_MANUAL_ENTRY: Indica si el usuario ingresó los datos de forma manual.
  • device.type: Debes especificar un tipo de dispositivo de uno de los tipos de Device admitidos.
  • device.manufacturer: Es el fabricante del dispositivo, por ejemplo, "Fitbit".
  • device.model: Es el modelo del dispositivo, por ejemplo, "Charge 3".
  • device.udi: (Opcional) Es la parte del identificador de dispositivo (DI) del identificador único de dispositivo (UDI) del dispositivo médico. Para obtener detalles sobre los permisos necesarios y los lineamientos de privacidad, consulta la guía de metadatos.

Configurar los metadatos correctamente es fundamental para la transparencia de los datos y ayuda a los usuarios a comprender de dónde proviene su información de salud. Para obtener todos los detalles, consulta la guía de metadatos de Health Connect.

Si los datos de tu app se importaron desde otra app, la responsabilidad de escribir sus propios datos en Health Connect recae en la otra app.

También es una buena idea implementar una lógica que maneje excepciones de escritura, como datos que están fuera de los límites o un error interno del sistema. Puedes aplicar tus estrategias de retirada y reintento en un mecanismo de programación de trabajos. Si la escritura en Health Connect no tiene éxito, asegúrate de que la app pueda superar ese punto de exportación. Recuerda informar y registrar errores para facilitar el diagnóstico.

Cuando realizas un seguimiento de los datos, hay algunas sugerencias que puedes seguir según la forma en que tu app escribe datos.

Manejo de zonas horarias

Cuando escribas registros basados en el tiempo, evita establecer compensaciones en zoneOffset.UTC de forma predeterminada, ya que esto puede generar marcas de tiempo inexactas cuando los usuarios se encuentran en otras zonas. En su lugar, calcula el desplazamiento según la ubicación real del dispositivo. Puedes recuperar la zona horaria del dispositivo con 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
)

Consulta la documentación de ZoneId para obtener más detalles.

Frecuencia y nivel de detalle de la escritura

Cuando escribas datos en Health Connect, usa la resolución adecuada. Usar la resolución adecuada ayuda a reducir la carga de almacenamiento, a la vez que se mantienen datos coherentes y precisos. La resolución de datos abarca dos aspectos:

  • Frecuencia de las operaciones de escritura: Es la frecuencia con la que tu aplicación escribe datos nuevos en Health Connect.
    • Escribe datos con la mayor frecuencia posible cuando haya datos nuevos disponibles, sin perder de vista el rendimiento del dispositivo.
    • Para evitar un impacto negativo en la duración de la batería y otros aspectos del rendimiento, el intervalo máximo entre escrituras debe ser de 15 minutos.
  • Nivel de detalle de los datos escritos: Es la frecuencia con la que se muestrearon los datos.
    • Por ejemplo, escribe muestras de frecuencia cardíaca cada 5 segundos.
    • No todos los tipos de datos requieren la misma tasa de muestreo. No es muy beneficioso actualizar los datos del recuento de pasos por segundo, en comparación con una cadencia menos frecuente, como cada 60 segundos.
    • Las tasas de muestreo más altas pueden dar a los usuarios un panorama más detallado de sus datos de salud y actividad física. Las tasas de muestreo deben alcanzar un equilibrio entre detalle y rendimiento.

Lineamientos adicionales

Sigue estos lineamientos cuando escribas datos:

  • En cada sincronización, solo escribe datos nuevos y actualiza los que se modificaron desde la última vez que se sincronizó.
  • Fragmenta las solicitudes a un máximo de 1,000 registros por solicitud de escritura.
  • Restringe las tareas para que se ejecuten solo cuando el dispositivo esté inactivo y no tenga poca batería.
  • Para las tareas en segundo plano, usa WorkManager para programar tareas periódicas, con un período máximo de 15 minutos.

En el siguiente código, se usa WorkManager para programar tareas periódicas en segundo plano, con un período máximo de 15 minutos y un intervalo flexible de 5 minutos. Esta configuración se establece con la clase PeriodicWorkRequest.Builder.

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

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

Seguimiento activo

Esto incluye las apps que realizan un seguimiento basado en eventos, como el ejercicio y el sueño, o las entradas manuales del usuario, como la nutrición. Estos registros se crean cuando la app está en primer plano o en eventos poco frecuentes en los que se usa algunas veces al día.

Verifica que la app no mantenga Health Connect en ejecución durante todo el evento.

Los datos deben escribirse en Health Connect de una de estas dos maneras:

  • Sincroniza los datos de Health Connect una vez completado el evento. Por ejemplo, sincroniza los datos cuando el usuario finaliza una sesión de ejercicio registrada.
  • Programa una tarea única con WorkManager para sincronizar los datos más tarde.

Prácticas recomendadas para la frecuencia y el nivel de detalle de las operaciones de escritura

Cuando escribas datos en Health Connect, usa la resolución adecuada. Usar la resolución adecuada ayuda a reducir la carga de almacenamiento, a la vez que se mantienen datos coherentes y precisos. La resolución de datos abarca 2 aspectos:

  1. Frecuencia de las operaciones de escritura: Es la frecuencia con la que tu aplicación envía datos nuevos a Health Connect. Escribe datos con la mayor frecuencia posible cuando haya datos nuevos disponibles, sin perder de vista el rendimiento del dispositivo. Para evitar un impacto negativo en la duración de la batería y otros aspectos del rendimiento, el intervalo máximo entre escrituras debe ser de 15 minutos.

  2. Nivel de detalle de los datos escritos: Es la frecuencia con la que se muestrearon los datos que se enviaron. Por ejemplo, escribe muestras de frecuencia cardíaca cada 5 s. No todos los tipos de datos requieren la misma tasa de muestreo. No es muy beneficioso actualizar los datos del recuento de pasos por segundo, en comparación con una cadencia menos frecuente, como cada 60 segundos. Sin embargo, las tasas de muestreo más altas pueden dar a los usuarios un panorama más detallado de sus datos de salud y actividad física. Las tasas de muestreo deben alcanzar un equilibrio entre detalle y rendimiento.

Estructura los registros para los datos de series

En el caso de los tipos de datos que usan una serie de muestras, como HeartRateRecord, es importante estructurar los registros correctamente. En lugar de crear un solo registro de un día de duración que se actualice constantemente, debes crear varios registros más pequeños, cada uno de los cuales represente un intervalo de tiempo específico.

Por ejemplo, para los datos de frecuencia cardíaca, debes crear un HeartRateRecord nuevo para cada minuto. Cada registro tendría una hora de inicio y una hora de finalización que abarcarían ese minuto, y contendría todas las muestras de frecuencia cardíaca capturadas durante ese minuto.

Durante las sincronizaciones periódicas con Health Connect (por ejemplo, cada 15 minutos), tu app debería escribir todos los registros de un minuto que se hayan creado desde la sincronización anterior. Esto mantiene los registros en un tamaño manejable y mejora el rendimiento de las consultas y el procesamiento de datos.

En el siguiente ejemplo, se muestra cómo crear un HeartRateRecord para un solo minuto, que contiene varias muestras:

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

Escribir datos supervisados durante todo el día

En el caso de los datos que se recopilan de forma continua, como los pasos, tu aplicación debe escribir en Health Connect con la mayor frecuencia posible cuando haya datos nuevos disponibles. Para evitar un impacto negativo en la duración de la batería y otros aspectos del rendimiento, el intervalo máximo entre escrituras debe ser de 15 minutos.

Tabla 1: Lineamientos para escribir datos

Tipo de datos

Unidad

Resultado esperado

Ejemplo

Pasos

pasos

Cada 1 minuto

23:14 - 23:15 - 5 pasos

23:16 - 23:17 - 22 pasos

23:17 - 23:18 - 8 pasos

StepsCadence

pasos/min

Cada 1 minuto

23:14 - 23:15 - 5 ppm

23:16 - 23:17 - 22 ppm

23:17 - 23:18 - 8 ppm

Impulsos en silla de ruedas

impulsos

Cada 1 minuto

23:14 - 23:15 - 5 flexiones

23:16 - 23:17 - 22 flexiones

23:17 - 23:18 - 8 empujones

ActiveCaloriesBurned

Calorías

Cada 15 minutos

23:15 - 23:30 - 2 calorías

23:30 - 23:45 - 25 calorías

23:45 - 00:00 - 5 calorías

TotalCaloriesBurned

Calorías

Cada 15 minutos

23:15 - 23:30 - 16 calorías

23:30 - 23:45 - 16 calorías

23:45 - 00:00 - 16 calorías

Distancia

km/min

Cada 1 minuto

23:14-23:15 - 0.008 km

23:16 - 23:16 - 0.021 km

23:17 - 23:18 - 0.012 km

ElevationGained

m

Cada 1 minuto

20:36 - 20:37 - 3.048m

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

FloorsClimbed

pisos

Cada 1 minuto

23:14 - 23:15 - 5 pisos

23:16 - 23:16 - 22 pisos

23:17 - 23:18 - 8 pisos

HeartRate

ppm

4 veces por minuto

6:11:15 a.m. - 55 ppm

6:11:30 a.m. - 56 ppm

6:11:45 a.m. - 56 ppm

6:12:00 a.m. - 55 ppm

HeartRateVariabilityRmssd

ms

Cada 1 minuto

6:11 a.m. - 23 ms

RespiratoryRate

respiraciones/minuto

Cada 1 minuto

23:14 - 23:15 - 60 respiraciones por minuto

23:16 - 23:16 - 62 respiraciones por minuto

23:17 - 23:18 - 64 respiraciones por minuto

OxygenSaturation

%

Cada 1 hora

6:11 - 95.208%

Los datos se deben escribir en Health Connect al final del entrenamiento o de la sesión de sueño. Para el monitoreo de actividades, como el ejercicio y el sueño, o las entradas manuales del usuario, como la nutrición, estos registros se crean cuando la app está en primer plano o en eventos poco frecuentes en los que se usa algunas veces al día.

Verifica que la app no mantenga Health Connect en ejecución durante todo el evento.

Los datos deben escribirse en Health Connect de una de estas dos maneras:

  • Sincroniza los datos de Health Connect una vez completado el evento. Por ejemplo, sincroniza los datos cuando el usuario finaliza una sesión de ejercicio registrada.
  • Programación de una tarea única con WorkManager para sincronizar los datos más tarde.

Sesiones de ejercicio y sueño

Como mínimo, tu aplicación debe seguir la orientación de la columna Esperado de la tabla 2. Cuando sea posible, sigue la orientación de la columna Mejor.

En la siguiente tabla, se muestra cómo escribir datos durante un ejercicio:

Tabla 2: Orientación para escribir datos durante una sesión de ejercicio

Tipo de datos

Unidad

Resultado esperado

Saludos

Ejemplo

Pasos

pasos

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 5 pasos

23:16 - 23:17 - 22 pasos

23:17 - 23:18 - 8 pasos

StepsCadence

pasos/min

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 35 ppm

23:16 - 23:17 - 37 ppm

23:17 - 23:18 - 40 ppm

Impulsos en silla de ruedas

impulsos

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 5 pushes

23:16 - 23:17 - 22 flexiones

23:17 - 23:18 - 8 empujones

CyclingPedalingCadence

rpm

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 65 rpm

23:16 - 23:17 - 70 rpm

23:17 - 23:18 - 68 rpm

Alimentación

vatios

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 250 vatios

23:16 - 23:17 - 255 vatios

23:17 - 23:18 - 245 vatios

Velocidad

km/min

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 0.3 km/min

23:16 - 23:17 - 0.4 km/min

23:17 - 23:18 -0.4 km/min

Distancia

km/m

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 0.008 km

23:16 - 23:16 - 0.021 km

23:17 - 23:18 - 0.012 km

ActiveCaloriesBurned

Calorías

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 20 calorías

23:16 - 23:17 - 20 calorías

23:17 - 23:18 - 25 calorías

TotalCaloriesBurned

Calorías

Cada 1 minuto

Cada 1 segundo

23:14-23:15 - 36 calorías

23:16 - 23:17 - 36 calorías

23:17 - 23:18 - 41 calorías

ElevationGained

m

Cada 1 minuto

Cada 1 segundo

20:36 - 20:37 - 3.048m

20:39 - 20:40 - 3.048m

23:23 - 23:24 - 9.144m

ExerciseRoutes

lat/lng/alt

Cada 3 a 5 segundos

Cada 1 segundo

HeartRate

ppm

4 veces por minuto

Cada 1 segundo

23:14-23:15 - 150 ppm

En la Tabla 3, se muestra cómo escribir datos durante o después de una sesión de sueño:

Tabla 3: Orientación para escribir datos durante o después de una sesión de sueño

Tipo de datos

Unidad

Muestras esperadas

Ejemplo

Etapas de sueño

de este proceso,

Período detallado por fase del sueño

23:46 - 23:50 - despierto/a

23:50 - 23:56 - sueño ligero

23:56 - 00:16 - deep sleep

RestingHeartRate

ppm

Un solo valor diario (se espera que se ingrese a primera hora de la mañana)

6:11 a.m. - 60 ppm

OxygenSaturation

%

Valor diario único (se espera a primera hora de la mañana)

6:11 - 95.208%

Eventos polideportivos

Este enfoque usa tipos y estructuras de datos existentes, y verifica la compatibilidad con las implementaciones y los lectores de datos actuales de Health Connect. Este es un enfoque común que adoptan las plataformas de fitness.

Además, las sesiones individuales, como natación, ciclismo y carrera, no están vinculadas de forma inherente en Health Connect, y los lectores de datos deben inferir la relación entre estas sesiones en función de su proximidad temporal. Las transiciones entre segmentos, como de natación a ciclismo, no se representan de forma explícita.

En el siguiente ejemplo, se muestra cómo escribir datos para un triatlón:

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

Controla excepciones

Health Connect genera excepciones estándar para las operaciones de CRUD cuando se produce un problema. Tu app debe detectar y controlar cada una de estas excepciones según corresponda.

Cada método de HealthConnectClient enumera las excepciones que se pueden generar. En general, tu app debe controlar las siguientes excepciones:

Tabla 1: Excepciones de Health Connect y prácticas recomendadas
Excepción Descripción Práctica recomendada
IllegalStateException Se produjo una de las siguientes situaciones:

  • El servicio de Health Connect no está disponible.
  • La solicitud no es una construcción válida. Por ejemplo, una solicitud agregada en buckets periódicos en la que se usa un objeto Instant para el timeRangeFilter.

Controla posibles problemas con las entradas antes de realizar una solicitud. Preferentemente, asigna valores a las variables o úsalos como parámetros dentro de una función personalizada en lugar de usarlos de forma directa en tus solicitudes para que puedas aplicar estrategias de manejo de errores.
IOException Se producen problemas al leer y escribir datos del disco. Para evitar este problema, estas son algunas sugerencias:

  • Crea una copia de seguridad de las entradas del usuario.
  • Ten la capacidad de controlar los problemas que ocurran durante las operaciones de escritura masiva. Por ejemplo, asegúrate de que el proceso pase el problema y lleve a cabo las operaciones restantes.
  • Aplica reintentos y estrategias de retirada para controlar los problemas de las solicitudes.

RemoteException Se produjeron errores en el servicio subyacente al que se conecta el SDK o en la comunicación con él.

Por ejemplo, tu app intenta borrar un registro con una uid determinada. Sin embargo, se arroja la excepción una vez que la app detecta que no existe el registro cuando se verifica en el servicio subyacente.
Para evitar este problema, estas son algunas sugerencias:

  • Realiza sincronizaciones frecuentes entre el almacén de datos de tu app y Health Connect.
  • Aplica reintentos y estrategias de retirada para controlar los problemas de las solicitudes.

SecurityException Se producen problemas cuando las solicitudes requieren permisos que no se otorgan. Para evitar esto, asegúrate de haber declarado el uso de los tipos de datos de Health Connect para tu app publicada. Además, debes declarar los permisos de Health Connect en el archivo de manifiesto y en tu actividad.