As atualizações de dados passivos são recomendadas para apps que precisam monitorar dados dos Recursos de saúde em segundo plano. Elas são destinadas a casos de uso que abrangem horas, dias ou até períodos mais longos. Se você precisa armazenar ou processar dados de saúde quando o app não estiver em execução e o usuário não estiver fazendo exercício, use o cliente passivo dos Recursos de saúde.
Para ver exemplos de uso de dados passivos, consulte o Dados passivos e Metas passivas no GitHub.
Adicionar dependências
Para adicionar uma dependência aos Recursos de saúde, é preciso adicionar o repositório Maven do Google ao seu projeto. Para mais informações, consulte a seção Repositório Maven do Google.
Adicione a dependência abaixo ao arquivo build.gradle
do módulo:
Groovy
dependencies { implementation "androidx.health:health-services-client:1.1.0-alpha03" }
Kotlin
dependencies { implementation("androidx.health:health-services-client:1.1.0-alpha03") }
Verificar os recursos
Antes de se registrar para atualizações de dados, verifique se o dispositivo pode fornecer o tipo de dados de que o app precisa. Ao verificar os recursos, você pode ativar ou desativar algumas funcionalidades ou mudar a interface do app para compensar aqueles que não estão disponíveis.
val healthClient = HealthServices.getClient(this /*context*/)
val passiveMonitoringClient = healthClient.passiveMonitoringClient
lifecycleScope.launchWhenCreated {
val capabilities = passiveMonitoringClient.capabilities.await()
// Supported types for passive data collection
supportsHeartRate =
DataType.HEART_RATE_BPM in capabilities.supportedDataTypesPassiveMonitoring
// Supported types for PassiveGoals
supportsStepsGoal =
DataType.STEPS_DAILY in capabilities.supportedDataTypesPassiveGoals
}
Registrar para dados passivos
É possível receber dados passivos usando um serviço ou um callback (ou ambos). Com um serviço, o app pode receber dados em segundo plano quando nenhuma parte dele estiver visível em primeiro plano. Os dados recebidos em segundo plano são enviados em lotes. O callback recebe dados a uma taxa um pouco mais rápida, mas apenas enquanto o app está em execução e o callback é notificado.
Seja qual for o método usado, primeiro crie uma PassiveListenerConfig
que determine os tipos de dados que serão recebidos, conforme mostrado no exemplo abaixo:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDataTypes(setOf(DataType.HEART_RATE_BPM))
.build()
Para receber dados usando um callback, defina e registre esse callback, como mostrado no exemplo abaixo:
val passiveListenerCallback: PassiveListenerCallback = object : PassiveListenerCallback {
override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
// TODO: Do something with dataPoints
}
}
passiveMonitoringClient.setPassiveListenerCallback(
passiveListenerConfig,
passiveListenerCallback
)
// To remove the listener
passiveMonitoringClient.clearPassiveListenerCallbackAsync()
O uso de um serviço é semelhante, mas, em vez de criar uma classe derivada de
PassiveListenerCallback
, derive de PassiveListenerService
, conforme mostrado no
exemplo abaixo:
class PassiveDataService : PassiveListenerService() {
override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
// TODO: Do something with dataPoints
}
}
passiveMonitoringClient.setPassiveListenerServiceAsync(
PassiveDataService::class.java,
passiveListenerConfig
)
Em seguida, declare o serviço no arquivo AndroidManifest.xml
. Exija uma permissão
de Recursos de saúde, que garante que somente esses recursos possam se vincular
ao serviço:
<service android:name=".PassiveDataService"
android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
android:exported="true" />
Interpretar o tempo
Os dados que você recebe dos Recursos de saúde são agrupados. Assim, você pode receber pontos de dados de tipos diferentes ou vários pontos de dados do mesmo tipo, no mesmo lote. Use os carimbos de data/hora incluídos nesses objetos em vez da hora em que foram recebidos pelo app para determinar a ordem correta dos eventos.
Para definir o carimbo de data/hora de cada DataPoint
, calcule primeiro a hora da inicialização,
conforme mostrado no exemplo abaixo:
val bootInstant =
Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())
Esse valor pode ser transmitido para
getStartInstant()
ou
getEndInstant()
.
Restaurar registros após a inicialização
Registros de dados passivos não são mantidos após as reinicializações. Para receber dados após a
reinicialização de um dispositivo, recrie seus registros usando um BroadcastReceiver
que
ouve a transmissão
do sistema
ACTION_BOOT_COMPLETED
.
Não tente restaurar os registros no receptor. Em vez disso,
delegue essa função a um worker WorkManager
. Quando o
dispositivo é inicializado, os Recursos de saúde podem levar dez segundos ou mais para
confirmar uma solicitação de registro de dados passivos, o que pode exceder o
tempo de execução permitido de um BroadcastReceiver
. Por outro lado, os workers WorkManager
têm um
limite de execução de dez minutos.
O snippet abaixo mostra como um BroadcastReceiver
pode ficar:
class StartupReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
// TODO: Check permissions first
WorkManager.getInstance(context).enqueue(
OneTimeWorkRequestBuilder<RegisterForPassiveDataWorker>().build()
)
}
}
class RegisterForPassiveDataWorker(
private val appContext: Context,
workerParams: WorkerParameters
) : Worker(appContext, workerParams) {
override fun doWork(): Result {
runBlocking {
HealthServices.getClient(appContext)
.passiveMonitoringClient
.setPassiveListenerCallback(...)
}
return Result.success()
}
}
Para que o sistema execute esse código quando o dispositivo for inicializado, faça
duas mudanças no AndroidManifest.xml
.
Primeiro, adicione a permissão abaixo como filha do <manifest>
:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Depois, adicione o filtro de intent de receptor abaixo como filho do <application>
:
<receiver
android:name=".StartupReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Estado da atividade
O cliente passivo também pode fornecer informações de alto nível sobre o estado do usuário, como se o usuário está dormindo. Para receber essas atualizações, siga estas etapas:
- Solicite a permissão
ACTIVITY_RECOGNITION
. - Chame
setShouldUserActivityInfoBeRequested(true)
no builderPassiveListenerConfig
.
Substitua o método onUserActivityInfoReceived()
no callback ou serviço
e use a UserActivityInfo
retornada, conforme mostrado no exemplo abaixo:
override fun onUserActivityInfoReceived(info: UserActivityInfo) {
val stateChangeTime: Instant = info.stateChangeTime // may be in the past!
val userActivityState: UserActivityState = info.userActivityState
if (userActivityState == UserActivityState.USER_ACTIVITY_ASLEEP) {
// ...
}
}
Metas passivas
É possível configurar um cliente passivo para notificar o app quando as metas passivas forem alcançadas, por exemplo, o usuário concluindo 10.000 passos em um dia.
Para fazer isso, crie uma meta, conforme mostrado no exemplo abaixo:
val dailyStepsGoal by lazy {
val condition = DataTypeCondition(
dataType = DataType.STEPS_DAILY,
threshold = 10_000, // Trigger every 10000 steps
comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
)
PassiveGoal(condition)
}
Adicione essa meta à PassiveListenerConfig
, conforme mostrado no exemplo
abaixo:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDailyGoals(setOf(dailyStepsGoal))
.build()
Substitua o método onGoalCompleted()
no callback ou serviço
e use o elemento PassiveGoal
retornado, conforme mostrado no exemplo abaixo:
override fun onGoalCompleted(goal: PassiveGoal) {
when (goal.dataTypeCondition.dataType) {
DataType.STEPS_DAILY -> {
// ...
}
}
}
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Exercícios e dados de atividade
- Começar a usar Blocos
- Adicionar uma tela de apresentação