Training mit TrainClient aufzeichnen

Google Health Services bietet über die ExerciseClient erstklassigen Support für Trainings-Apps. Mit ExerciseClient kann Ihre App steuern, wann ein Training läuft, Trainingsziele hinzufügen und Updates zum Trainingsstatus, zu Trainingsereignissen oder zu anderen gewünschten Messwerten erhalten. Weitere Informationen finden Sie in der vollständigen Liste der Übungstypen, die von den Gesundheitsdiensten unterstützt werden.

Sehen Sie sich das Beispiel für die Übung auf GitHub an.

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 dann in 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")
}

App-Struktur

Verwenden Sie die folgende App-Struktur, wenn Sie eine Trainings-App mit Gesundheitsdiensten erstellen:

Bei der Vorbereitung auf ein Training und während des Trainings kann Ihre Aktivität aus verschiedenen Gründen beendet werden. Der Nutzer kann zu einer anderen App wechseln oder zum Zifferblatt zurückkehren. Möglicherweise wird etwas über Ihrer Aktivität angezeigt oder das Display schaltet sich nach einer bestimmten Zeit ohne Aktivität aus. Verwenden Sie eine kontinuierlich laufende ForegroundService in Verbindung mit ExerciseClient, um den ordnungsgemäßen Betrieb während des gesamten Trainings sicherzustellen.

Wenn Sie ein ForegroundService verwenden, können Sie mit der Ongoing Activity API eine Anzeige auf Ihren Smartwatch-Oberflächen anzeigen lassen, damit Nutzer schnell zum Training zurückkehren können.

Es ist wichtig, dass Sie Standortdaten in Ihrem Dienst im Vordergrund ordnungsgemäß anfordern. Geben Sie in Ihrer Manifestdatei die erforderlichen Typen von Diensten im Vordergrund und Berechtigungen an:

<manifest ...>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <application ...>
    
      <!-- If your app is designed only for devices that run Wear OS 4
           or lower, use android:foregroundServiceType="location" instead. -->
      <service
          android:name=".MyExerciseSessionRecorder"
          android:foregroundServiceType="health|location">
      </service>
      
    </application>
</manifest>

Verwende AmbientLifecycleObserver für die Aktivität vor dem Training, die den prepareExercise()-Aufruf enthält, und für die Trainingsaktivität. Aktualisieren Sie das Display während des Trainings jedoch nicht, wenn sich das Display im Ruhemodus befindet. Das liegt daran, dass Trainingsdaten von den Gesundheitsdiensten im Batchverfahren verarbeitet werden, wenn sich das Display im Ruhemodus befindet, um Strom zu sparen. Die angezeigten Informationen sind daher möglicherweise nicht aktuell. Während eines Trainings sollten Daten angezeigt werden, die für den Nutzer sinnvoll sind. Zeigen Sie entweder aktuelle Informationen oder einen leeren Bildschirm an.

Funktionen prüfen

Jede ExerciseType unterstützt bestimmte Datentypen für Messwerte und Trainingsziele. Prüfen Sie diese Funktionen beim Starten, da sie je nach Gerät variieren können. Ein Gerät unterstützt möglicherweise keinen bestimmten Trainingstyp oder keine bestimmte Funktion, z. B. die automatische Pause. Außerdem können sich die Funktionen eines Geräts im Laufe der Zeit ändern, z. B. nach einem Softwareupdate.

Beim Starten der App die Gerätefunktionen abfragen und Folgendes speichern und verarbeiten:

  • Die Übungen, die von der Plattform unterstützt werden.
  • Die für die einzelnen Übungen unterstützten Funktionen.
  • Die für jede Übung unterstützten Datentypen.
  • Die für jeden dieser Datentypen erforderlichen Berechtigungen.

Wenn Sie ExerciseCapabilities.getExerciseTypeCapabilities() mit dem gewünschten Trainingstyp verwenden, sehen Sie, welche Messwerte Sie anfordern, welche Trainingsziele Sie konfigurieren und welche anderen Funktionen für diesen Typ verfügbar sind. Das ist im folgenden Beispiel zu sehen:

val healthClient = HealthServices.getClient(this /*context*/)
val exerciseClient = healthClient.exerciseClient
lifecycleScope.launch {
    val capabilities = exerciseClient.getCapabilitiesAsync().await()
    if (ExerciseType.RUNNING in capabilities.supportedExerciseTypes) {
        runningCapabilities =
            capabilities.getExerciseTypeCapabilities(ExerciseType.RUNNING)
    }
}

Im zurückgegebenen ExerciseTypeCapabilities sind unter supportedDataTypes die Datentypen aufgeführt, für die Sie Daten anfordern können. Das ist von Gerät zu Gerät unterschiedlich. Achten Sie darauf, keine DataType anzufordern, die nicht unterstützt wird, da Ihre Anfrage sonst fehlschlagen kann.

Anhand der Felder supportedGoals und supportedMilestones können Sie feststellen, ob die Übung ein Trainingsziel unterstützen kann, das Sie erstellen möchten.

Wenn Nutzer in Ihrer App die automatische Pausierung verwenden können, müssen Sie prüfen, ob diese Funktion vom Gerät unterstützt wird. Verwenden Sie dazu supportsAutoPauseAndResume. ExerciseClient lehnt Anfragen ab, die auf dem Gerät nicht unterstützt werden.

Im folgenden Beispiel wird die Unterstützung für den Datentyp HEART_RATE_BPM, die Zielvorhabenfunktion STEPS_TOTAL und die Funktion zur automatischen Pausierung geprüft:

// Whether we can request heart rate metrics.
supportsHeartRate = DataType.HEART_RATE_BPM in runningCapabilities.supportedDataTypes

// Whether we can make a one-time goal for aggregate steps.
val stepGoals = runningCapabilities.supportedGoals[DataType.STEPS_TOTAL]
supportsStepGoals = 
    (stepGoals != null && ComparisonType.GREATER_THAN_OR_EQUAL in stepGoals)

// Whether auto-pause is supported.
val supportsAutoPause = runningCapabilities.supportsAutoPauseAndResume

Für Updates zum Trainingsstatus registrieren

Trainingsupdates werden an einen Listener gesendet. Ihre App kann jeweils nur einen einzelnen Listener registrieren. Richten Sie den Listener vor Beginn des Trainings ein, wie im folgenden Beispiel gezeigt. Der Empfänger erhält nur Updates zu Übungen, die Ihrer App gehören.

val callback = object : ExerciseUpdateCallback {
    override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
        val exerciseStateInfo = update.exerciseStateInfo
        val activeDuration = update.activeDurationCheckpoint
        val latestMetrics = update.latestMetrics
        val latestGoals = update.latestAchievedGoals
    }

    override fun onLapSummaryReceived(lapSummary: ExerciseLapSummary) {
        // For ExerciseTypes that support laps, this is called when a lap is marked.
    }

    override fun onAvailabilityChanged(
        dataType: DataType<*, *>,
        availability: Availability
    ) {
        // Called when the availability of a particular DataType changes.
        when {
            availability is LocationAvailability -> // Relates to Location/GPS.
            availability is DataTypeAvailability -> // Relates to another DataType.
        }
    }
}
exerciseClient.setUpdateCallback(callback)

Lebensdauer der Übung verwalten

Die Gesundheitsdienste unterstützen maximal eine Übung gleichzeitig in allen Apps auf dem Gerät. Wenn eine Aktivität erfasst wird und eine andere App mit dem Erfassen einer neuen Aktivität beginnt, wird die erste Aktivität beendet.

Führen Sie vor Beginn der Übung die folgenden Schritte aus:

  • Prüfen, ob eine Übung bereits erfasst wird, und entsprechend reagieren Bitten Sie den Nutzer beispielsweise um Bestätigung, bevor Sie ein vorheriges Training überschreiben und mit dem Erfassen eines neuen beginnen.

Das folgende Beispiel zeigt, wie Sie mit getCurrentExerciseInfoAsync nach einer vorhandenen Übung suchen:

lifecycleScope.launch {
    val exerciseInfo = exerciseClient.getCurrentExerciseInfoAsync().await()
    when (exerciseInfo.exerciseTrackedStatus) {
        OTHER_APP_IN_PROGRESS -> // Warn user before continuing, will stop the existing workout.
        OWNED_EXERCISE_IN_PROGRESS -> // This app has an existing workout.
        NO_EXERCISE_IN_PROGRESS -> // Start a fresh workout.
    }
}

Berechtigungen

Achten Sie bei der Verwendung von ExerciseClient darauf, dass Ihre App die erforderlichen Berechtigungen anfordert und beibehält. Wenn Ihre App LOCATION-Daten verwendet, muss sie auch die entsprechenden Berechtigungen anfordern und verwalten.

Führe für alle Datentypen vor dem Aufrufen von prepareExercise() oder startExercise() die folgenden Schritte aus:

  • Geben Sie in Ihrer AndroidManifest.xml-Datei die entsprechenden Berechtigungen für die angeforderten Datentypen an.
  • Prüfen Sie, ob der Nutzer die erforderlichen Berechtigungen erteilt hat. Weitere Informationen finden Sie unter App-Berechtigungen anfordern. Health Services lehnt die Anfrage ab, wenn die erforderlichen Berechtigungen nicht bereits gewährt wurden.

Führen Sie für Standortdaten die folgenden zusätzlichen Schritte aus:

Training vorbereiten

Einige Sensoren wie GPS oder Herzfrequenz benötigen möglicherweise etwas Zeit zum Aufwärmen. Möglicherweise möchte der Nutzer auch seine Daten sehen, bevor er mit dem Training beginnt. Mit der optionalen Methode prepareExerciseAsync() können diese Sensoren aufgewärmt und Daten empfangen werden, ohne dass der Timer für das Training gestartet wird. Die activeDuration ist von dieser Vorbereitungszeit nicht betroffen.

Prüfen Sie vor dem Anruf bei prepareExerciseAsync() Folgendes:

  • Prüfen Sie die plattformweite Standorteinstellung. Diese Einstellung wird vom Nutzer im Hauptmenü „Einstellungen“ gesteuert. Sie unterscheidet sich von der Berechtigungsprüfung auf App-Ebene.

    Wenn die Einstellung deaktiviert ist, informieren Sie den Nutzer darüber, dass er den Zugriff auf die Standortermittlung verweigert hat, und bitten Sie ihn, sie zu aktivieren, wenn Ihre App die Standortermittlung benötigt.

  • Prüfen Sie, ob Ihre App Laufzeitberechtigungen für Körpersensoren (API-Level 35 oder niedriger) oder Puls (API-Level 36 oder höher), Aktivitätserkennung und Standortermittlung hat. Wenn Berechtigungen fehlen, bitten Sie den Nutzer, Laufzeitberechtigungen zu gewähren, und geben Sie einen angemessenen Kontext an. Wenn der Nutzer eine bestimmte Berechtigung nicht erteilt, entfernen Sie die mit dieser Berechtigung verknüpften Datentypen aus dem Aufruf von prepareExerciseAsync(). Wenn weder Körpersensoren (Herzfrequenz auf API-Ebene 36 und höher) noch Standortberechtigungen gewährt werden, rufe prepareExerciseAsync() nicht auf. Der Vorbereitungsaufruf dient speziell dazu, vor Beginn eines Trainings eine stabile Herzfrequenz oder GPS-Fix zu erhalten. Die App kann weiterhin schrittbasierte Entfernung, Schritttempo, Geschwindigkeit und andere Messwerte abrufen, für die diese Berechtigungen nicht erforderlich sind.

So sorgen Sie dafür, dass Ihr Aufruf von prepareExerciseAsync() erfolgreich ist:

  • Verwende AmbientLifecycleObserver für die Aktivität vor dem Training, die den prepare-Aufruf enthält.
  • Rufen Sie prepareExerciseAsync() über Ihren Dienst im Vordergrund auf. Wenn sich der Sensor nicht in einem Dienst befindet und mit dem Aktivitätszyklus verknüpft ist, wird die Sensorvorbereitung möglicherweise unnötig beendet.
  • Rufen Sie endExercise() auf, um die Sensoren auszuschalten und den Energieverbrauch zu senken, wenn der Nutzer die Aktivität vor dem Training verlässt.

Das folgende Beispiel zeigt, wie prepareExerciseAsync() aufgerufen wird:

val warmUpConfig = WarmUpConfig(
    ExerciseType.RUNNING,
    setOf(
        DataType.HEART_RATE_BPM,
        DataType.LOCATION
    )
)
// Only necessary to call prepareExerciseAsync if body sensor (API level 35
// or lower), heart rate (API level 36+), or location permissions are given.
exerciseClient.prepareExerciseAsync(warmUpConfig).await()

// Data and availability updates are delivered to the registered listener.

Sobald sich die App im Status PREPARING befindet, werden Updates zur Sensorverfügbarkeit in den Status ExerciseUpdateCallback bis onAvailabilityChanged() gesendet. Diese Informationen können dann dem Nutzer angezeigt werden, damit er entscheiden kann, ob er mit dem Training beginnen möchte.

Training starten

Wenn Sie eine Übung starten möchten, erstellen Sie eine ExerciseConfig, um den Übungstyp, die Datentypen, für die Sie Messwerte erhalten möchten, und alle Übungsziele oder -meilensteine zu konfigurieren.

Trainingsziele bestehen aus einem DataType und einer Bedingung. Trainingsziele sind einmalige Ziele, die ausgelöst werden, wenn eine Bedingung erfüllt ist, z. B. wenn der Nutzer eine bestimmte Strecke zurücklegt. Es kann auch ein Meilenstein für das Training festgelegt werden. Trainingsmeilensteine können mehrmals ausgelöst werden, z. B. jedes Mal, wenn der Nutzer eine bestimmte Strecke zurückgelegt hat.

Im folgenden Beispiel wird gezeigt, wie Sie ein Ziel für jeden Typ erstellen:

const val CALORIES_THRESHOLD = 250.0
const val DISTANCE_THRESHOLD = 1_000.0 // meters

suspend fun startExercise() {
    // Types for which we want to receive metrics.
    val dataTypes = setOf(
        DataType.HEART_RATE_BPM,
        DataType.CALORIES_TOTAL,
        DataType.DISTANCE
    )

    // Create a one-time goal.
    val calorieGoal = ExerciseGoal.createOneTimeGoal(
        DataTypeCondition(
            dataType = DataType.CALORIES_TOTAL,
            threshold = CALORIES_THRESHOLD,
            comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
        )
    )

    // Create a milestone goal. To make a milestone for every kilometer, set the initial
    // threshold to 1km and the period to 1km.
    val distanceGoal = ExerciseGoal.createMilestone(
        condition = DataTypeCondition(
            dataType = DataType.DISTANCE_TOTAL,
            threshold = DISTANCE_THRESHOLD,
            comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
        ),
        period = DISTANCE_THRESHOLD
    )

    val config = ExerciseConfig(
        exerciseType = ExerciseType.RUNNING,
        dataTypes = dataTypes,
        isAutoPauseAndResumeEnabled = false,
        isGpsEnabled = true,
        exerciseGoals = mutableListOf<ExerciseGoal<Double>>(calorieGoal, distanceGoal)
    )
    exerciseClient.startExerciseAsync(config).await()
}

Sie können auch für alle Übungen Runden markieren. Gesundheitsdienste stellen eine ExerciseLapSummary mit Messwerten bereit, die über den gesamten Erfassungszeitraum aggregiert wurden.

Im vorherigen Beispiel wird die Verwendung von isGpsEnabled gezeigt, die beim Anfordern von Standortdaten wahr sein muss. Die Verwendung von GPS kann jedoch auch bei anderen Messwerten hilfreich sein. Wenn in ExerciseConfig die Entfernung als DataType angegeben ist, wird standardmäßig die Entfernung in Schritten geschätzt. Wenn Sie optional GPS aktivieren, können Standortinformationen anstelle der Schrittzahl verwendet werden, um die Entfernung zu schätzen.

Training pausieren, fortsetzen und beenden

Sie können Trainings mit der entsprechenden Methode pausieren, fortsetzen und beenden, z. B. mit pauseExerciseAsync() oder endExerciseAsync().

Verwenden Sie den Status von ExerciseUpdate als „Source of Truth“. Das Training gilt nicht als pausiert, wenn der Aufruf von pauseExerciseAsync() zurückgegeben wird, sondern wenn dieser Status in der ExerciseUpdate-Nachricht widergespiegelt wird. Dies ist besonders wichtig, wenn es um UI-Status geht. Wenn der Nutzer auf „Pausieren“ drückt, deaktivieren Sie die Schaltfläche „Pausieren“ und rufen Sie pauseExerciseAsync() für den Gesundheitsdienst an. Warten Sie mit ExerciseUpdate.exerciseStateInfo.state, bis die Gesundheitsdienste den Status „Pausiert“ erreichen, und stellen Sie dann die Schaltfläche auf „Fortsetzen“ um. Das liegt daran, dass es länger dauern kann, bis Statusaktualisierungen für die Gesundheitsdienste zugestellt werden, als bis die Schaltfläche gedrückt wird. Wenn Sie also alle Änderungen an der Benutzeroberfläche an Schaltflächendrücke binden, kann die Benutzeroberfläche nicht mehr mit dem Status der Gesundheitsdienste synchronisiert werden.

Beachten Sie dies in den folgenden Fällen:

  • Die automatische Pausenfunktion ist aktiviert:Das Training kann ohne Nutzerinteraktion pausiert oder gestartet werden.
  • Eine andere App startet ein Training:Ihr Training wird möglicherweise ohne Nutzerinteraktion beendet.

Wenn das Training Ihrer App von einer anderen App beendet wird, muss Ihre App die Beendigung ordnungsgemäß verarbeiten:

  • Speichern Sie den Status des teilweisen Trainings, damit der Fortschritt eines Nutzers nicht gelöscht wird.
  • Entfernen Sie das Symbol für laufende Aktivitäten und senden Sie dem Nutzer eine Benachrichtigung, dass sein Training von einer anderen App beendet wurde.

Berücksichtigen Sie auch den Fall, dass Berechtigungen während einer laufenden Übung widerrufen werden. Dieser wird mit dem Status isEnded und einer ExerciseEndReason von AUTO_END_PERMISSION_LOST gesendet. Gehe mit diesem Fall ähnlich wie bei der Kontoschließung vor: Speichere den teilweisen Status, entferne das Symbol für laufende Aktivitäten und sende eine Benachrichtigung über das, was mit dem Nutzer passiert ist.

Im folgenden Beispiel wird gezeigt, wie die Beendigung korrekt geprüft wird:

val callback = object : ExerciseUpdateCallback {
    override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
        if (update.exerciseStateInfo.state.isEnded) {
            // Workout has either been ended by the user, or otherwise terminated
        }
        ...
    }
    ...
}

Dauer der Aktivität verwalten

Während einer Übung kann eine App die aktive Dauer des Trainings anzeigen. Die App, die Gesundheitsdienste und die Microcontroller-Einheit (MCU) des Geräts – der energieeffiziente Prozessor, der für das Erfassen von Aktivitäten verantwortlich ist – müssen synchronisiert sein und dieselbe aktuelle aktive Dauer haben. Zur besseren Verwaltung sendet der Dienst „Gesundheit“ eine ActiveDurationCheckpoint, die einen Ankerpunkt liefert, von dem aus die App ihren Timer starten kann.

Da die aktive Dauer von der MCU gesendet wird und es etwas dauern kann, bis sie in der App ankommt, enthält ActiveDurationCheckpoint zwei Properties:

  • activeDuration: wie lange die Übung aktiv ist
  • time: Zeitpunkt, zu dem die aktive Dauer berechnet wurde

Daher kann die aktive Dauer einer Übung in der App anhand von ActiveDurationCheckpoint mithilfe der folgenden Gleichung berechnet werden:

(now() - checkpoint.time) + checkpoint.activeDuration

So wird das kleine Delta zwischen der aktiven Dauer, die auf der MCU berechnet wird, und der Zeit, zu der sie in der App ankommt, berücksichtigt. So kann ein Chronometer in der App gestartet werden und der Timer der App ist genau auf die Zeit in den Gesundheitsdiensten und der MCU abgestimmt.

Wenn die Übung pausiert ist, wartet die App, bis die berechnete Zeit die auf der Benutzeroberfläche angezeigte Zeit überschritten hat, bevor sie den Timer auf der Benutzeroberfläche neu startet. Das liegt daran, dass das Pausierungssignal die Health Services und die MCU mit einer leichten Verzögerung erreicht. Wenn die App beispielsweise bei t=10 Sekunden pausiert wird, liefert Health Services das PAUSED-Update möglicherweise erst bei t=10, 2 Sekunden an die App.

Mit Daten von ExerciseClient arbeiten

Messwerte für die Datentypen, für die Ihre App registriert ist, werden in ExerciseUpdate-Nachrichten gesendet.

Der Prozessor sendet Nachrichten nur, wenn er aktiv ist oder ein maximaler Meldezeitraum erreicht wird, z. B. alle 150 Sekunden. Verwende die ExerciseUpdate-Frequenz nicht, um einen Chronometer mit der activeDuration weiterzuschalten. Im Beispiel für das Training auf GitHub finden Sie ein Beispiel für die Implementierung eines unabhängigen Chronometers.

Wenn ein Nutzer ein Training startet, können ExerciseUpdate-Nachrichten häufig gesendet werden, z. B. jede Sekunde. Wenn der Nutzer das Training startet, wird der Bildschirm möglicherweise ausgeschaltet. Gesundheitsdienste können dann weniger häufig Daten senden, werden aber weiterhin mit derselben Häufigkeit abgetastet, um das Aufwecken des Hauptprozessors zu vermeiden. Wenn der Nutzer auf den Bildschirm schaut, werden alle Daten, die gerade in Batches verarbeitet werden, sofort an Ihre App gesendet.

Batch-Frequenz steuern

In einigen Fällen möchten Sie möglicherweise festlegen, wie oft Ihre App bestimmte Datentypen empfängt, während das Display ausgeschaltet ist. Mit einem BatchingMode-Objekt kann Ihre App das standardmäßige Batch-Verhalten überschreiben, um Daten häufiger zu erhalten.

So konfigurieren Sie die Batch-Rate:

  1. Prüfen Sie, ob die jeweilige BatchingMode-Definition vom Gerät unterstützt wird:

    // Confirm BatchingMode support to control heart rate stream to phone.
    suspend fun supportsHrWorkoutCompanionMode(): Boolean {
        val capabilities = exerciseClient.getCapabilities()
        return BatchingMode.HEART_RATE_5_SECONDS in
                capabilities.supportedBatchingModeOverrides
    }
    
  2. Geben Sie an, dass das ExerciseConfig-Objekt eine bestimmte BatchingMode verwenden soll, wie im folgenden Code-Snippet gezeigt.

    val config = ExerciseConfig(
        exerciseType = ExerciseType.WORKOUT,
        dataTypes = setOf(
            DataType.HEART_RATE_BPM,
            DataType.TOTAL_CALORIES
        ),
        // ...
        batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    )
    
  3. Optional kannst du BatchingMode während des Trainings dynamisch konfigurieren, anstatt ein bestimmtes Batching-Verhalten während der gesamten Dauer des Trainings beizubehalten:

    val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
    
  4. Wenn Sie die benutzerdefinierte BatchingMode löschen und zum Standardverhalten zurückkehren möchten, übergeben Sie einen leeren Satz an exerciseClient.overrideBatchingModesForActiveExercise().

Zeitstempel

Der Zeitpunkt jedes Datenpunkts entspricht der Dauer seit dem Start des Geräts. So wandeln Sie diese in einen Zeitstempel um:

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

Dieser Wert kann dann für jeden Datenpunkt mit getStartInstant() oder getEndInstant() verwendet werden.

Richtigkeit der Daten

Bei einigen Datentypen können jedem Datenpunkt Genauigkeitsinformationen zugeordnet sein. Das wird durch das Attribut accuracy dargestellt.

Die Klassen HrAccuracy und LocationAccuracy können jeweils für die Datentypen HEART_RATE_BPM und LOCATION ausgefüllt werden. Verwenden Sie gegebenenfalls das Attribut accuracy, um festzustellen, ob die einzelnen Datenpunkte für Ihre Anwendung ausreichend genau sind.

Daten speichern und hochladen

Verwenden Sie Room, um von Health Services übermittelte Daten zu speichern. Der Datenupload erfolgt am Ende der Übung mit einem Mechanismus wie dem Work Manager. So werden Netzwerkanrufe zum Hochladen von Daten bis zum Ende der Übung verschoben, wodurch der Energieverbrauch während der Übung minimiert und die Arbeit vereinfacht wird.

Liste zur Überprüfung der Einbindung

Bevor Sie Ihre App veröffentlichen, die die ExerciseClient von Gesundheitsdiensten verwendet, sehen Sie sich die folgende Checkliste an, um häufige Probleme zu vermeiden. Sind die folgenden Voraussetzungen erfüllt?

  • Ihre App prüft die Funktionen des Trainingstyps und des Geräts jedes Mal, wenn sie ausgeführt wird. So können Sie erkennen, wenn ein bestimmtes Gerät oder eine bestimmte Übung keinen der Datentypen unterstützt, die für Ihre App erforderlich sind.
  • Sie fordern die erforderlichen Berechtigungen an, verwalten sie und geben sie in Ihrer Manifestdatei an. Bevor prepareExerciseAsync() aufgerufen wird, bestätigt Ihre App, dass die Laufzeitberechtigungen erteilt wurden.
  • In Ihrer App wird getCurrentExerciseInfoAsync() verwendet, um in folgenden Fällen zu reagieren:
    • Es wird bereits ein Training aufgezeichnet und Ihre App überschreibt das vorherige Training.
    • Eine andere App hat Ihr Training beendet. Wenn der Nutzer die App wieder öffnet, wird ihm möglicherweise eine Meldung angezeigt, dass die Übung beendet wurde, weil eine andere App übernommen hat.
  • Wenn Sie LOCATION-Daten verwenden:
    • Ihre App verwaltet während der gesamten Dauer des Trainings (einschließlich des Aufrufs zum Vorbereiten) einen ForegroundService mit der entsprechenden foregroundServiceType.
    • Prüfen Sie mit isProviderEnabled(LocationManager.GPS_PROVIDER), ob GPS auf dem Gerät aktiviert ist, und fordern Sie den Nutzer gegebenenfalls auf, die Standorteinstellungen zu öffnen.
    • Bei anspruchsvollen Anwendungsfällen, bei denen es wichtig ist, Standortdaten mit geringer Latenz zu erhalten, sollten Sie den Fused Location Provider (FLP) einbinden und seine Daten als erste Standortbestimmung verwenden. Wenn von den Gesundheitsdiensten stabilere Standortinformationen verfügbar sind, verwenden Sie diese anstelle von FLP.
  • Wenn für Ihre App ein Datenupload erforderlich ist, werden alle Netzwerkaufrufe zum Hochladen von Daten bis zum Ende der Übung verschoben. Ansonsten führt Ihre App während der gesamten Übung nur sparsam notwendige Netzwerkaufrufe aus.