Daten im Hintergrund überwachen

Passive Datenupdates eignen sich für Apps, die Gesundheitsdienste überwachen müssen im Hintergrund ausgeführt werden. Sie sind für Anwendungsfälle gedacht, die Stunden, Tage oder noch länger. Wenn Sie Gesundheitsdaten speichern oder verarbeiten müssen, läuft und der Nutzer nicht explizit an einer Übung teilnimmt, verwende Der passive Client des Health Service.

Beispiele für die passive Datennutzung finden Sie auf der Passive Daten und Passive Ziele auf GitHub.

Abhängigkeiten hinzufügen

Wenn Sie eine Abhängigkeit von Health Services hinzufügen möchten, müssen Sie das Google Maven-Repository hinzufügen zu Ihrem Projekt hinzufügen. Weitere Informationen finden Sie unter Maven-Repository von Google.

Fügen Sie in der Datei build.gradle auf Modulebene die folgende Abhängigkeit hinzu:

Groovy

dependencies {
    implementation "androidx.health:health-services-client:1.1.0-alpha04"
}

Kotlin

dependencies {
    implementation("androidx.health:health-services-client:1.1.0-alpha04")
}

Funktionen prüfen

Bevor Sie sich für Datenupdates registrieren, prüfen Sie, ob das Gerät den Typ die Ihre App benötigt. Mit der Überprüfung der Funktionen können Sie Funktionen ändern oder die Benutzeroberfläche Ihrer App ändern, um Funktionen zu kompensieren, nicht verfügbar.

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. A kann Ihre App Daten im Hintergrund empfangen, wenn kein Teil Ihres App im Vordergrund zu sehen ist. Wenn Sie Daten im Hintergrund empfangen, in Batches bereitgestellt. Der Callback empfängt Daten etwas schneller, während die App ausgeführt wird und der Callback erfolgreich benachrichtigt wird.

Unabhängig von der verwendeten Methode müssen Sie zuerst ein PassiveListenerConfig erstellen. bestimmt, welche Datentypen empfangen werden sollen, wie im folgenden Beispiel gezeigt:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDataTypes(setOf(DataType.HEART_RATE_BPM))
    .build()

Um Daten über einen Callback zu empfangen, definieren und registrieren Sie den Callback, wie in im folgenden Beispiel:

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, aber anstatt eine Klasse zu erstellen, die aus PassiveListenerCallback, abgeleitet von PassiveListenerService, wie in im folgenden Beispiel:

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. Gesundheitszustand erforderlich Berechtigung „Dienste“, mit der sichergestellt wird, dass nur Gesundheitsdienste eine Bindung herstellen können an den Dienst:

<service android:name=".PassiveDataService"
    android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
    android:exported="true" />

Zeit interpretieren

Die Daten, die du von Health Services erhältst, werden in Batches zusammengefasst, sodass du Daten empfangen kannst unterschiedlichen Typen oder mehrere Datenpunkte desselben Typs im selben zu erstellen. Verwenden Sie anstelle der Uhrzeit die in diesen Objekten enthaltenen Zeitstempel die von Ihrer App empfangen wurden, um die richtige Reihenfolge der Ereignisse zu bestimmen.

Um Zeitstempel für jede DataPoint zu erhalten, berechnen Sie zuerst den Bootzeitstempel. Dies wird im folgenden Beispiel gezeigt:

val bootInstant =
    Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())

Dieser Wert kann dann an getStartInstant() oder getEndInstant()

Registrierungen nach dem Booten wiederherstellen

Passive Datenregistrierungen gehen bei Neustarts nicht verloren. Um Daten zu empfangen, nachdem dein Gerät neu gestartet wurde, erstelle deine Registrierungen mit einem BroadcastReceiver neu, der auf das Ereignis ACTION_BOOT_COMPLETED Systemnachricht an.

Versuchen Sie nicht, die Registrierungen im Empfänger direkt wiederherzustellen. Stattdessen Sie können diese Funktion an einen WorkManager-Worker delegieren. Wenn der Parameter Gerät gestartet wird, kann es 10 Sekunden oder länger dauern, bis eine passive Datenregistrierungsanfrage bestätigen. Dies könnte die zulässige Ausführungszeit einer BroadcastReceiver. Im Gegensatz dazu: WorkManager Arbeiter:innen haben: 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 Hochfahren des Geräts ausführt, zwei Änderungen an der Datei AndroidManifest.xml.

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 dann den folgenden Empfänger-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, wie ob der Nutzer schläft. So erhalten Sie Updates:

  1. Fordern Sie die Berechtigung ACTIVITY_RECOGNITION an.
  2. Rufen Sie setShouldUserActivityInfoBeRequested(true) in der PassiveListenerConfig-Builder.

onUserActivityInfoReceived()-Methode in Ihrem Callback oder Dienst überschreiben und verwenden den zurückgegebenen 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 über passive Ziele benachrichtigt wird erreicht werden, z. B. wenn der Nutzer 10.000 Schritte an einem Tag ausführt.

Erstellen Sie dazu ein Zielvorhaben wie im folgenden Beispiel:

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 wie unten gezeigt Ihrem PassiveListenerConfig hinzu Beispiel:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDailyGoals(setOf(dailyStepsGoal))
    .build()

onGoalCompleted()-Methode in Ihrem Callback oder Dienst überschreiben und verwenden den zurückgegebenen PassiveGoal, wie im folgenden Beispiel gezeigt:

override fun onGoalCompleted(goal: PassiveGoal) {
    when (goal.dataTypeCondition.dataType) {
        DataType.STEPS_DAILY -> {
            // ...
        }
    }
}