Desenvolver experiências de sinais vitais com a Conexão Saúde

Este guia é compatível com a versão 1.1.0 ou mais recente do app Conexão Saúde.

Se você quer criar um app que gerencie os sinais vitais do usuário, use a Conexão Saúde para:

  • Ler dados de sinais vitais, como pressão arterial, frequência cardíaca e temperatura corporal, de outros apps
  • Gravar dados de sinais vitais registrados pelo app ou por dispositivos conectados
  • Monitorar tendências e fornecer insights de saúde com base em dados de sinais vitais

Este guia descreve como trabalhar com tipos de dados de sinais vitais, incluindo permissões, fluxos de trabalho de leitura e gravação e práticas recomendadas.

Visão geral: como criar um rastreador de sinais vitais abrangente

Para criar uma experiência abrangente de monitoramento de sinais vitais usando a Conexão Saúde, siga estas etapas principais:

  • Solicitar as permissões adequadas para os tipos de dados de sinais vitais.
  • Gravar dados de sinais vitais usando registros como BloodPressureRecord, HeartRateRecord e outros registros de sinais vitais.
  • Ler dados de sinais vitais para exibição, análise ou sincronização.
  • Usar o processamento em lote para gravar e ler dados de forma eficiente.

Esse fluxo de trabalho permite a interoperabilidade com outros apps da Conexão Saúde e verifica o acesso aos dados controlado pelo usuário.

Antes de começar

Antes de implementar os recursos de sinais vitais:

Principais conceitos

Os dados de sinais vitais no Conexão Saúde são representados por vários tipos de registro, cada um correspondendo a uma medição fisiológica específica. Ao contrário das sessões de treino, os sinais vitais geralmente são registrados como dados pontuais ou baseados em intervalos.

Tipos de dados de sinais vitais

Os dados de sinais vitais são representados por tipos de registro individuais. Alguns tipos comuns são:

  • BloodPressureRecord: representa uma única leitura de pressão arterial, incluindo pressão sistólica e diastólica e posição do corpo.
  • HeartRateRecord: representa uma série de medições de frequência cardíaca.
  • RestingHeartRateRecord: representa uma única medição da frequência cardíaca em repouso.
  • BodyTemperatureRecord: representa uma única leitura de temperatura corporal, incluindo o local da medição.
  • BloodGlucoseRecord: representa uma única leitura de glicemia, incluindo a relação com a refeição e a origem da amostra.
  • OxygenSaturationRecord: representa uma única leitura de saturação de oxigênio no sangue.
  • RespiratoryRateRecord: representa uma única medição do ritmo respiratório.

Para uma lista completa, consulte Tipos de dados do Conexão Saúde.

Considerações de desenvolvimento

Os dados de sinais vitais podem ser sensíveis, e os apps podem precisar gravar dados em resposta a medições de sensores ou entradas do usuário, ou sincronizar dados de um back-end. As permissões são essenciais para lidar com dados de sinais vitais.

Permissões

O app precisa solicitar as permissões relevantes do Conexão Saúde antes de ler ou gravar dados de sinais vitais. As permissões comuns para sinais vitais incluem pressão arterial, frequência cardíaca, temperatura corporal, glicemia, saturação de oxigênio e ritmo respiratório. Isso inclui o seguinte:

O exemplo a seguir mostra como solicitar permissões para pressão arterial, frequência cardíaca e temperatura corporal:

Depois de criar uma instância de cliente, seu app precisa solicitar permissões aos usuários. Os usuários precisam concedê-las ou negá-las a qualquer momento. Para fazer isso, crie um conjunto de permissões para os tipos de dados necessários. Verifique se as permissões no conjunto foram declaradas no manifesto do Android primeiro.

val permissions =
    setOf(
        HealthPermission.getReadPermission(BloodPressureRecord::class),
        HealthPermission.getWritePermission(BloodPressureRecord::class),
        HealthPermission.getReadPermission(HeartRateRecord::class),
        HealthPermission.getWritePermission(HeartRateRecord::class),
        HealthPermission.getReadPermission(BodyTemperatureRecord::class),
        HealthPermission.getWritePermission(BodyTemperatureRecord::class)
    )
Use getGrantedPermissions para verificar se o app já tem as permissões necessárias concedidas. Caso contrário, use createRequestPermissionResultContract para solicitá-las. Isso mostra a tela de permissões da Conexão Saúde.
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.") }
    }
}
Como os usuários podem conceder ou revogar permissões a qualquer momento, seu app precisa verificar as permissões sempre antes de usá-las e lidar com situações em que elas são perdidas.

Para solicitar permissões, chame a função checkPermissionsAndRun:

if (!granted.containsAll(permissions)) {
    // Check if required permissions are not granted, and return
    return emptySet()
}
// Permissions already granted; proceed with inserting or reading data

Se você só precisar solicitar permissões para um único tipo de dado, como pressão arterial, inclua apenas esse tipo no conjunto de permissões:

O acesso à pressão arterial é protegido pelas seguintes permissões:

  • android.permission.health.READ_BLOOD_PRESSURE
  • android.permission.health.WRITE_BLOOD_PRESSURE

Para adicionar a capacidade de pressão arterial ao app, solicite permissões para o tipo de dados BloodPressureRecord.

Confira a permissão necessária para poder gravar a pressão arterial:

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

Para ler a pressão arterial, você precisa solicitar as seguintes permissões:

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

Gravar dados de sinais vitais

Nesta seção, descrevemos como gravar dados de sinais vitais no Conexão Saúde. Os dados de sinais vitais costumam ser gravados como registros individuais. Se você estiver gravando vários registros de uma só vez, como ao sincronizar de um sensor ou back-end, use o processamento em lote.

Exemplo de como escrever um BloodPressureRecord:

suspend fun writeBloodPressureRecord(healthConnectClient: HealthConnectClient) {
    val record = BloodPressureRecord(
        time = Instant.now(),
        zoneOffset = ZoneOffset.UTC,
        systolic = Pressure.millimetersOfMercury(120.0),
        diastolic = Pressure.millimetersOfMercury(80.0),
        bodyPosition = BloodPressureRecord.BODY_POSITION_SITTING_DOWN,
        measurementLocation = BloodPressureRecord.MEASUREMENT_LOCATION_LEFT_WRIST
    )
    healthConnectClient.insertRecords(listOf(record))
}

Gravação em lote

Se o app precisar gravar vários pontos de dados, como sincronizar dados de um dispositivo conectado ou de um serviço de back-end, faça gravações em lote para melhorar a eficiência e reduzir o consumo de bateria. O Conexão Saúde pode processar até 1.000 registros em uma única solicitação de gravação.

O código a seguir mostra como gravar vários registros em lote de uma só vez:

suspend fun writeBatchRecords(healthConnectClient: HealthConnectClient) {
    val bloodPressureRecord = BloodPressureRecord(
        time = Instant.now(),
        zoneOffset = ZoneOffset.UTC,
        systolic = Pressure.millimetersOfMercury(120.0),
        diastolic = Pressure.millimetersOfMercury(80.0),
        bodyPosition = BloodPressureRecord.BODY_POSITION_SITTING_DOWN,
        measurementLocation = BloodPressureRecord.MEASUREMENT_LOCATION_LEFT_WRIST
    )
    val heartRateRecord = HeartRateRecord(
        startTime = Instant.now().minusSeconds(60),
        startZoneOffset = ZoneOffset.UTC,
        endTime = Instant.now(),
        endZoneOffset = ZoneOffset.UTC,
        samples = listOf(HeartRateRecord.Sample(time = Instant.now().minusSeconds(30), beatsPerMinute = 80))
    )
    healthConnectClient.insertRecords(listOf(bloodPressureRecord, heartRateRecord))
}

Ler dados de sinais vitais

Os apps podem ler dados de sinais vitais para mostrar medições, analisar tendências ou sincronizar dados com um servidor externo. Para ler os sinais vitais, use um ReadRecordsRequest com o tipo de registro específico e filtre por um período.

Exemplo de leitura de dados de BloodPressureRecord:

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

    for (record in response.records) {
        // Process each blood pressure record
        val systolic = record.systolic
        val diastolic = record.diastolic
    }
}

Se você precisar sincronizar dados de sinais vitais com um servidor de back-end ou manter o repositório de dados do seu app atualizado com o Conexão Saúde, use os registros de alterações. Isso permite recuperar uma lista de registros inseridos, atualizados ou excluídos desde um momento específico, o que é mais eficiente do que rastrear manualmente as mudanças ou ler repetidamente todos os dados. Para mais informações, consulte Sincronizar dados com a Conexão Saúde.

Práticas recomendadas

Siga estas diretrizes para melhorar a confiabilidade dos dados e a experiência do usuário:

  • Solicitações de gravação em lote: para reduzir a sobrecarga de entrada/saída e preservar a duração da bateria, agrupe os pontos de dados em uma única chamada insertRecords com lotes de até 1.000 registros, em vez de gravar cada ponto individualmente.
  • Gravar com frequência durante o monitoramento em tempo real: para atualizações frequentes de sensores (como monitores contínuos de glicose ou de frequência cardíaca), grave dados em lotes em intervalos de até 15 minutos para equilibrar as atualizações em tempo real com a eficiência da bateria.
  • Use o WorkManager para sincronizações em segundo plano: use o WorkManager para gravações adiadas, como a sincronização de dados de um dispositivo complementar ou serviço de back-end. Tente usar um intervalo de 15 minutos para gravações em lote.
  • Evite gravar dados duplicados: use IDs de cliente: ao criar registros, defina um metadata.clientRecordId. O Conexão Saúde usa isso para identificar registros exclusivos. Se você tentar gravar um registro com um clientRecordId que já existe, a Conexão Saúde vai ignorar a cópia ou atualizar o registro atual em vez de criar um novo. Definir um metadata.clientRecordId é a maneira mais eficaz de evitar duplicatas durante novas tentativas de sincronização ou reinstalações de apps.
    val record = StepsRecord(
        count = 100,
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "daily_steps_2023_10_27_user_123"
        )
    )
  • Verificar os dados atuais: antes de sincronizar os dados, consulte a Conexão Saúde para encontrar registros no período de sincronização e conferir se os dados do seu app já existem, evitando duplicatas ou a substituição de dados mais recentes.
  • Forneça justificativas claras para a permissão: use o fluxo Permission.createIntent para explicar por que o app precisa de acesso aos dados de saúde, por exemplo: "Para monitorar suas tendências de pressão arterial e fornecer insights".
  • Alinhar os carimbos de data/hora com as medições: verifique se os carimbos de data/hora dos registros refletem com precisão quando as medições foram feitas. Para dados de intervalo como HeartRateRecord, verifique se startTime e endTime estão corretos.

Teste

Para verificar a precisão dos dados e garantir uma experiência do usuário de alta qualidade, siga estas estratégias de teste e consulte a documentação oficial Testar os principais casos de uso.

Ferramentas de verificação

  • Caixa de ferramentas do Conexão Saúde:use esse app complementar para inspecionar manualmente registros, excluir dados de teste e simular mudanças no banco de dados. É a melhor maneira de verificar se os registros estão sendo armazenados corretamente.
  • Teste de unidade com FakeHealthConnectClient:use a biblioteca de testes para verificar como o app lida com casos extremos, como revogação de permissões ou exceções de API, sem precisar de um dispositivo físico.

Checklist de qualidade

Arquitetura típica

Uma implementação de métricas geralmente inclui:

Componente Gerencia
Controlador de sinais vitais Leitura de sensor/entrada
Lógica de loteamento
Camada de repositório (envolve as operações do Conexão Saúde): Inserir registros de sinais vitais
Ler registros de sinais vitais
Camada de interface (telas): Leituras em tempo real
Dados históricos
Gráficos e tendências

Solução de problemas

Sintoma Possível causa Resolução
Tipos de dados ausentes (por exemplo, pressão arterial) Permissões de gravação ausentes ou filtros de tempo incorretos. Verifique se você solicitou e se o usuário concedeu a permissão para o tipo de dados específico. Verifique se o ReadRecordsRequest usa um TimeRangeFilter que abrange o horário da medição. Consulte Permissões.
Registros duplicados aparecem clientRecordId ausente. Atribua um clientRecordId exclusivo no Metadata de cada registro. Isso permite que a Conexão Saúde elimine duplicações se os mesmos dados forem gravados duas vezes durante uma nova tentativa de sincronização. Consulte as práticas recomendadas.
Falha ao gravar registros Unidades incorretas ou valores fora do intervalo válido. A Conexão Saúde valida os valores de registro. Por exemplo, os valores de pressão arterial precisam estar em um intervalo fisiologicamente plausível. Consulte a documentação do tipo de dados para ver os intervalos e as unidades válidos.

Etapas comuns de depuração

Verifique o estado da permissão. Sempre chame getPermissionStatus() antes de tentar uma operação de leitura ou gravação. Os usuários podem revogar as permissões nas configurações do sistema a qualquer momento.