Passive Datenaktualisierungen eignen sich für Apps, die Health Services-Daten im Hintergrund überwachen müssen. Sie sind für Anwendungsfälle vorgesehen, die Stunden, Tage oder sogar länger dauern. Wenn Sie Gesundheits- und Fitnessdaten speichern oder verarbeiten müssen, wenn Ihre App nicht ausgeführt wird und der Nutzer nicht explizit trainiert, verwenden Sie den passiven Client des Health Service.
Beispiele für die Verwendung passiver Daten finden Sie in den Beispielen Passive Data und Passive Goals auf GitHub.
Abhängigkeiten hinzufügen
Wenn Sie eine Abhängigkeit von Health Services hinzufügen möchten, müssen Sie Ihrem Projekt das Google Maven-Repository hinzufügen. Weitere Informationen finden Sie im Maven-Repository von Google.
Fügen Sie der Datei build.gradle
auf Modulebene die folgende Abhängigkeit hinzu:
Groovy
dependencies { implementation "androidx.health:health-services-client:1.1.0-alpha05" }
Kotlin
dependencies { implementation("androidx.health:health-services-client:1.1.0-alpha05") }
Funktionen prüfen
Prüfen Sie vor der Registrierung für Datenaktualisierungen, ob das Gerät den Datentyp bereitstellen kann, den Ihre App benötigt. Durch die Prüfung von Funktionen können Sie bestimmte Funktionen aktivieren oder deaktivieren oder die Benutzeroberfläche Ihrer App anpassen, um Funktionen zu kompensieren, die nicht verfügbar sind.
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
}
Für passive Daten registrieren
Sie können passive Daten über einen Dienst, einen Callback oder beides empfangen. Mit einem Dienst kann Ihre App Daten im Hintergrund empfangen, wenn kein Teil Ihrer App im Vordergrund sichtbar ist. Wenn Sie Daten im Hintergrund empfangen, werden sie in Batches übertragen. Über den Callback werden Daten etwas schneller empfangen, aber nur, wenn die App ausgeführt wird und der Callback erfolgreich benachrichtigt wurde.
Unabhängig davon, welche Methode Sie verwenden, müssen Sie zuerst ein PassiveListenerConfig
erstellen, das festlegt, welche Datentypen empfangen werden sollen. Das folgende Beispiel zeigt, wie das geht:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDataTypes(setOf(DataType.HEART_RATE_BPM))
.build()
Wenn Sie Daten über einen Callback empfangen möchten, müssen Sie den Callback definieren und registrieren, wie im folgenden Beispiel gezeigt:
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()
Die Verwendung eines Dienstes ist ähnlich. Anstatt eine Klasse zu erstellen, die von PassiveListenerCallback
abgeleitet ist, leiten Sie sie von PassiveListenerService
ab, wie im folgenden Beispiel gezeigt:
class PassiveDataService : PassiveListenerService() {
override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
// TODO: Do something with dataPoints
}
}
passiveMonitoringClient.setPassiveListenerServiceAsync(
PassiveDataService::class.java,
passiveListenerConfig
)
Als Nächstes deklarieren Sie den Dienst in der Datei AndroidManifest.xml
. Erfordert eine Health Services-Berechtigung, die bestätigt, dass nur Health Services eine Bindung an den Dienst vornehmen kann:
<service android:name=".PassiveDataService"
android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
android:exported="true" />
Zeit interpretieren
Die Daten, die Sie von Health Services erhalten, werden in Batches zusammengefasst. Sie können also Datenpunkte verschiedener Typen oder mehrere Datenpunkte desselben Typs im selben Batch erhalten. Verwenden Sie die in diesen Objekten enthaltenen Zeitstempel anstelle der Zeit, zu der sie von Ihrer App empfangen wurden, um die richtige Reihenfolge der Ereignisse zu bestimmen.
Rufen Sie Zeitstempel für jedes DataPoint
ab, indem Sie zuerst den Boot-Zeitstempel berechnen, wie im folgenden Beispiel gezeigt:
val bootInstant =
Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())
Dieser Wert kann dann an getStartInstant()
oder getEndInstant()
übergeben werden.
Registrierungen nach dem Start wiederherstellen
Passive Datenregistrierungen bleiben nach Neustarts nicht erhalten. Wenn Sie nach dem Neustart eines Geräts Daten empfangen möchten, müssen Sie Ihre Registrierungen mit einem BroadcastReceiver
neu erstellen, das auf den Systembroadcast ACTION_BOOT_COMPLETED
wartet.
Versuche nicht, die Registrierungen direkt auf dem Empfängergerät wiederherzustellen. Delegieren Sie diese Funktion stattdessen an einen WorkManager
-Worker. Beim Starten des Geräts kann es 10 Sekunden oder länger dauern, bis Health Services eine Anfrage zur Registrierung passiver Daten bestätigen. Dies kann die zulässige Ausführungszeit eines BroadcastReceiver
überschreiten. Im Gegensatz dazu haben WorkManager
-Worker ein Ausführungslimit von 10 Minuten.
Das folgende Snippet zeigt, wie ein BroadcastReceiver
aussehen könnte:
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()
}
}
Damit das System diesen Code beim Starten des Geräts ausführt, müssen Sie zwei Änderungen an der Datei AndroidManifest.xml
vornehmen.
Fügen Sie zuerst die folgende Berechtigung als untergeordnetes Element von <manifest>
hinzu:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Fügen Sie als Nächstes den folgenden Receiver-Intent-Filter als untergeordnetes Element von <application>
hinzu:
<receiver
android:name=".StartupReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Aktivitätsstatus
Der passive Client kann auch allgemeine Informationen zum Nutzerstatus liefern, z. B. ob der Nutzer schläft. So erhalten Sie diese Updates:
- Fordern Sie die Berechtigung
ACTIVITY_RECOGNITION
an. - Rufen Sie
setShouldUserActivityInfoBeRequested(true)
imPassiveListenerConfig
-Builder auf.
Überschreiben Sie die Methode onUserActivityInfoReceived()
in Ihrem Callback oder Dienst und verwenden Sie die zurückgegebene UserActivityInfo
, wie im folgenden Beispiel gezeigt:
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) {
// ...
}
}
Passive Ziele
Sie können einen passiven Client so konfigurieren, dass die App benachrichtigt wird, wenn passive Ziele erreicht werden, z. B. wenn der Nutzer an einem Tag 10.000 Schritte zurückgelegt hat.
Erstellen Sie dazu ein Ziel, wie im folgenden Beispiel gezeigt:
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)
}
Fügen Sie dieses Zielvorhaben Ihrem PassiveListenerConfig
hinzu, wie im folgenden Beispiel gezeigt:
val passiveListenerConfig = PassiveListenerConfig.builder()
.setDailyGoals(setOf(dailyStepsGoal))
.build()
Überschreiben Sie die Methode onGoalCompleted()
in Ihrem Callback oder Dienst und verwenden Sie die zurückgegebene PassiveGoal
, wie im folgenden Beispiel gezeigt:
override fun onGoalCompleted(goal: PassiveGoal) {
when (goal.dataTypeCondition.dataType) {
DataType.STEPS_DAILY -> {
// ...
}
}
}
Empfehlungen für dich
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Aktive Daten und Übungen
- Kacheln verwenden
- Splash Screen hinzufügen