Se você quiser criar uma experiência de monitoramento do sono no seu app, use o Conexão Saúde para fazer o seguinte:
- Gravar sessões de sono
- Gravar dados de estágio do sono
- Gravar dados de sono, como frequência cardíaca, saturação de oxigênio e frequência respiratória
- Ler dados de sono de outros apps
Este guia descreve como criar esses recursos de sono, abordando tipos de dados, execução em segundo plano, permissões, fluxos de trabalho recomendados e práticas recomendadas.
Visão geral: como criar um monitor de sono abrangente
Para criar uma experiência de monitoramento do sono abrangente usando o Conexão Saúde, siga estas etapas principais:
- Implementar corretamente as permissões com base nas permissões de saúde.
- Gravar sessões usando
SleepSessionRecord. - Gravar tipos de dados, como estágios do sono, frequência cardíaca e saturação de oxigênio de forma consistente durante a sessão.
- Gerenciar a execução em segundo plano corretamente para verificar a captura contínua de dados durante a noite.
- Ler dados de sessão para resumos e análises pós-sono.
Esse fluxo de trabalho permite a interoperabilidade com outros apps do Conexão Saúde e verifica o acesso aos dados controlado pelo usuário.
Antes de começar
Antes de implementar recursos de sono:
- Integre o Conexão Saúde usando a dependência apropriada.
- Crie uma instância de
HealthConnectClient. - Verifique se o app implementa fluxos de permissão de execução com base nas permissões de saúde.
Principais conceitos
O Conexão Saúde representa dados de sono usando alguns componentes principais. Um SleepSessionRecord atua como o registro central do sono, contendo detalhes como horários de início ou término e estágios do sono. Durante uma sessão, vários tipos de dados, como HeartRateRecord ou OxygenSaturationRecord, podem ser gravados.
Sessões de sono
Os dados de sono são representados por SleepSessionRecord. Cada registro armazena:
startTimeendTimestages: uma lista deSleepSessionRecord.Stage, incluindo sono profundo, leve, REM e acordado.- Metadados de sessão opcionais (título, observações)
Os apps podem gravar vários tipos de dados associados a uma sessão.
Tipos de dados
Os tipos de dados comuns gravados durante uma sessão de sono incluem:
SleepSessionRecord: registra a duração e os estágios do sono, incluindo sono profundo, leve, REM e acordado.HeartRateRecord: registra a frequência cardíaca durante o sono.OxygenSaturationRecord: registra a saturação de oxigênio (SpO2) durante o sono.RespiratoryRateRecord: registra a frequência respiratória durante o sono.
Cada tipo de dado é armazenado como um registro individual.
Considerações de desenvolvimento
Os apps de monitoramento do sono geralmente precisam ser executados por períodos prolongados, com frequência em segundo plano quando a tela está desligada. Ao criar seus recursos de sono, é importante considerar como gerenciar a execução em segundo plano e solicitar as permissões necessárias para dados de sono.
Execução em segundo plano
Os apps de monitoramento do sono geralmente são executados durante a noite com a tela desligada. Nesse estado, use:
- Serviços em primeiro plano para coleta de dados
WorkManagerpara gravação ou sincronização adiada- Estratégias de lote para gravações de registro regulares de dados granulares, como frequência cardíaca
Mantenha a continuidade mantendo o ID da sessão consistente em todas as gravações.
Permissões
O app precisa solicitar as permissões relevantes do Conexão Saúde antes de ler ou gravar dados de sono. Para conferir uma lista completa de tipos de dados, consulte Tipos de dados do Conexão Saúde. As permissões comuns para o sono incluem sessões de sono e métricas como frequência cardíaca ou saturação de oxigênio.
O acesso ao sono é protegido pelas seguintes permissões:
android.permission.health.READ_SLEEPandroid.permission.health.WRITE_SLEEP
Para adicionar a capacidade de sono ao app, comece solicitando permissões para o tipo de dados SleepSession.
Confira a permissão necessária para poder gravar o sono:
<application>
<uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>
Para ler o sono, é necessário solicitar as seguintes permissões:
<application>
<uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>
O exemplo a seguir mostra como solicitar permissões para uma sessão de sono que inclui dados de frequência cardíaca, saturação de oxigênio e frequência respiratória:
Depois de criar uma instância de cliente, seu app precisa solicitar permissões aos usuários. Os usuários precisam poder conceder ou negar permissões 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 primeiro no manifesto do 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)
)
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.
// 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)
}
}
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 cenários em que a permissão é perdida.
Implementar uma sessão de sono
Esta seção descreve o fluxo de trabalho recomendado para gravar dados de sono.
Para alinhar tipos de dados como HeartRateRecord ou OxygenSaturationRecord a uma sessão de sono, grave-os com carimbos de data/hora que estejam entre o startTime e o endTime da sessão. O Conexão Saúde não usa um identificador de sessão para vincular sessões de sono a dados granulares. Em vez disso, a associação é implícita por intervalos de tempo sobrepostos. Ao ler dados de sono, você pode usar o período de uma sessão
para consultar tipos de dados associados, conforme mostrado em
Ler dados de sono.
Gravar uma sessão
Embora dados granulares, como frequência cardíaca, possam ser gravados durante uma sessão de sono, o SleepSessionRecord só poderá ser gravado no Conexão Saúde depois que a sessão terminar, por exemplo, quando o usuário acordar. O
registro precisa incluir o
startTime, o endTime da sessão e uma lista de SleepSessionRecord.Stage
gravados durante a sessão, já que SleepSessionRecord exige que endTime
seja posterior a startTime.
Para gravar uma sessão de sono:
- Gere um ID de registro de cliente exclusivo.
- Quando o usuário acordar ou o monitoramento do sono for interrompido, colete todos os estágios do sono e construa um
SleepSessionRecord. - Insira o registro usando
insertRecords.
Exemplo:
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))
Ler dados de sono
Os apps podem ler sessões de sono e os dados associados para resumir a atividade, fornecer insights de saúde ou sincronizar dados com um servidor externo. Por exemplo, você pode ler um SleepSessionRecord e consultar o HeartRateRecord que ocorreu durante o mesmo intervalo de tempo.
Ler sessão com dados associados
É possível ler sessões de sono usando um ReadRecordsRequest com SleepSessionRecord como o tipo de registro, filtrado por um período. Para ler dados associados de uma determinada sessão, faça uma segunda solicitação para o tipo de dados selecionado, como HeartRateRecord, filtrando pelo startTime e endTime da sessão de sono.
O exemplo a seguir mostra como ler sessões de sono com dados de frequência cardíaca associados para um determinado período:
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
}
}
}
}
Práticas recomendadas
Siga estas diretrizes para melhorar a confiabilidade dos dados e a experiência do usuário:
- Grave com frequência durante o monitoramento ativo: para o monitoramento ativo, grave os dados assim que eles ficarem disponíveis ou em um intervalo máximo de 15 minutos.
- Use o WorkManager para sincronizações em segundo plano: use
WorkManagerpara gravações adiadas. Procure um intervalo de 15 minutos para encontrar um equilíbrio entre dados em tempo real e eficiência da bateria. - Solicitações de gravação em lote: não grave cada evento de sensor individualmente. Divida suas solicitações. O Conexão Saúde processa até 1.000 registros por solicitação de gravação.
- Mantenha os IDs de sessão estáveis e exclusivos: use identificadores consistentes para suas sessões. Se uma sessão for editada ou atualizada, o uso do mesmo ID impedirá que ela seja tratada como uma sessão nova e separada.
- Use o lote para tipos de dados: para reduzir a sobrecarga de entrada/saída e preservar a vida útil da bateria, agrupe seus pontos de dados em uma única chamada
insertRecordsem vez de gravar cada ponto individualmente. - 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 umclientRecordIdque já existe, o Conexão Saúde vai ignorar o duplicado ou atualizar o registro atual em vez de criar um novo. Definir ummetadata.clientRecordIdé a maneira mais eficaz de evitar duplicados 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" ) )
- Verifique os dados atuais: antes de sincronizar, consulte o período para verificar se os registros do seu app já existem.
- Verifique se os carimbos de data/hora não se sobrepõem: verifique se uma nova sessão não começa antes que a anterior termine. Sessões sobrepostas podem causar conflitos em painéis de fitness e cálculos de resumo.
- Forneça justificativas claras para a permissão: use o fluxo
Permission.createIntentpara explicar por que o app precisa de acesso a dados de saúde, por exemplo: "Para monitorar as tendências de pressão arterial e fornecer insights". - Teste sessões de longa duração: monitore o consumo de bateria durante sessões que duram várias horas para verificar se o intervalo de lote e o uso do sensor não esgotam o dispositivo.
- Alinhe os carimbos de data/hora com as taxas de sensor: combine os carimbos de data/hora do registro com a frequência real dos sensores para manter a alta fidelidade dos dados.
Teste
Para verificar a correção dos dados e uma experiência do usuário de alta qualidade, siga estas estratégias de teste e consulte a documentação oficial de casos de uso principais de teste.
Ferramentas de verificação
- Caixa de ferramentas do Conexão Saúde: use esse app complementar para inspecionar registros manualmente, excluir dados de teste e simular mudanças no banco de dados. Essa é 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 processa casos extremos, como revogação de permissão ou exceções de API, sem precisar de um dispositivo físico.
Checklist de qualidade
Arquitetura típica
Uma implementação de monitoramento do sono geralmente inclui:
| Componente | Gerencia |
|---|---|
| Controlador de sessão | Estado da sessão Temporizador Lógica de lote Controladores de tipos de dados Coleta de dados |
| Camada de repositório (encapsula operações do Conexão Saúde): | Inserir sessão Inserir tipos de dados Insere estágios do sono Ler resumos de sessão |
| Camada de interface (mostra): | Duração Tipos de dados ativos Visualização do estágio do sono |
Solução de problemas
| Sintoma | Possível causa | Resolução |
|---|---|---|
| Tipos de dados ausentes (por exemplo, frequência cardíaca) | Permissões de gravação ausentes ou filtros de tempo incorretos. | Verifique se você solicitou e o usuário concedeu a permissão de tipo de dados específica. Verifique se o ReadRecordsRequest usa um TimeRangeFilter que corresponde à sessão. Consulte Permissões. |
| Falha na gravação da sessão | Carimbos de data/hora sobrepostos. | O Conexão Saúde pode rejeitar registros que se sobrepõem aos dados atuais do mesmo app. Valide se o startTime de uma nova sessão é posterior ao endTime da anterior. |
| Nenhum dado do sensor gravado durante o sono | O serviço em primeiro plano foi encerrado ou está inativo. | Para coletar dados do sensor durante a noite enquanto a tela está desligada, use um serviço em primeiro plano com foregroundServiceType="health". |
| Registros duplicados aparecem | clientRecordId ausente. |
Atribua um clientRecordId exclusivo no Metadata de cada registro. Isso permite que o Conexão Saúde execute a desduplicação se os mesmos dados forem gravados duas vezes durante uma nova tentativa de sincronização. Consulte Práticas recomendadas. |
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 permissões nas configurações do sistema a qualquer momento. |
| Verifique o modo de execução. | Se o app não estiver coletando dados em segundo plano, verifique se você declarou as permissões corretas no arquivo AndroidManifest.xml e se o usuário não colocou o app no modo "Restrição de bateria". |