Training mit TrainClient aufzeichnen

Health Services bietet Unterstützung für Trainings-Apps über die ExerciseClient. Mit ExerciseClient kann deine App steuern, wann ein Training läuft, Trainingsziele hinzufügen und Updates zum Trainingsstatus, zu Trainingsereignissen oder zu anderen Messwerten erhalten. Eine vollständige Liste der von Health Services unterstützten Trainingsarten findest du hier.

Beispiel für Übung auf GitHub ansehen

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

Verwende die folgende App-Struktur, wenn du eine Trainings-App mit Health Services entwickelst:

Wenn du dich auf ein Training vorbereitest und während des Trainings kann deine Aktivität aus verschiedenen Gründen beendet werden. Der Nutzer wechselt möglicherweise zu einer anderen App oder kehrt zum Zifferblatt zurück. Das System zeigt möglicherweise etwas über Ihrer Aktivität an oder der Bildschirm schaltet sich nach einer bestimmten Zeit der Inaktivität aus. Verwende einen kontinuierlich laufenden ForegroundService in Verbindung mit ExerciseClient, um einen korrekten Betrieb während des gesamten Trainings zu gewährleisten.

Mit einem ForegroundService können Sie die Ongoing Activity API verwenden, um auf Ihren Zifferblättern einen Indikator anzuzeigen, damit der Nutzer schnell zum Training zurückkehren kann.

Es ist wichtig, dass Sie Standortdaten in Ihrem Vordergrunddienst angemessen 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 deine Aktivität vor dem Training, die den prepareExercise()-Aufruf enthält, und für deine Trainingsaktivität. Aktualisiere das Display während des Trainings jedoch nicht im Inaktivmodus, da Health Services Trainingsdaten im Inaktivmodus des Gerätedisplays zusammenfasst, um Strom zu sparen. Die angezeigten Informationen sind daher möglicherweise nicht aktuell. Während des Trainings werden Daten angezeigt, die für den Nutzer relevant sind. Entweder werden aktuelle Informationen oder ein leerer Bildschirm angezeigt.

Funktionen prüfen

Jedes ExerciseType unterstützt bestimmte Datentypen für Messwerte und Trainingsziele. Prüfe diese Funktionen beim Start, da sie je nach Gerät variieren können. Ein Gerät unterstützt möglicherweise nicht alle Trainingstypen oder bestimmte Funktionen wie die automatische Pause. Außerdem können sich die Funktionen eines Geräts im Laufe der Zeit ändern, z. B. nach einem Softwareupdate.

Fragen Sie beim Start der App die Gerätefunktionen ab und speichern und verarbeiten Sie Folgendes:

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

Mit ExerciseCapabilities.getExerciseTypeCapabilities() kannst du dir für die ausgewählte Trainingsart ansehen, welche Messwerte du anfordern kannst, welche Trainingsziele du konfigurieren kannst und welche anderen Funktionen für diese Art verfügbar sind. Dies wird im folgenden Beispiel veranschaulicht:

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 werden unter supportedDataTypes die Datentypen aufgeführt, für die Sie Daten anfordern können. Das variiert je nach Gerät. Achten Sie also darauf, keine DataType anzufordern, die nicht unterstützt wird, da Ihre Anfrage sonst möglicherweise fehlschlägt.

Anhand der Felder supportedGoals und supportedMilestones kannst du feststellen, ob das Training ein Trainingsziel unterstützt, das du erstellen möchtest.

Wenn Ihre App die automatische Pausierung unterstützt, müssen Sie mit supportsAutoPauseAndResume prüfen, ob diese Funktion vom Gerät unterstützt wird. ExerciseClient lehnt Anfragen ab, die auf dem Gerät nicht unterstützt werden.

Im folgenden Beispiel wird geprüft, ob der Datentyp HEART_RATE_BPM, die Zielvorhabenfunktion STEPS_TOTAL und die Funktion zum automatischen Pausieren unterstützt werden:

// 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 Zuhörer gesendet. Ihre App kann jeweils nur einen Listener registrieren. Richte den Listener ein, bevor du mit dem Training beginnst, wie im folgenden Beispiel gezeigt. Der Listener erhält nur Updates zu Übungen, die zu 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 von Übungen verwalten

Health Services unterstützt maximal ein Training gleichzeitig für alle Apps auf dem Gerät. Wenn ein Training aufgezeichnet wird und eine andere App mit der Aufzeichnung eines neuen Trainings beginnt, wird das erste Training beendet.

Führe vor dem Start des Trainings folgende Schritte aus:

  • Prüfe, ob ein Training bereits aufgezeichnet wird, und reagiere entsprechend. Bitten Sie den Nutzer beispielsweise um Bestätigung, bevor Sie ein vorheriges Training überschreiben und ein neues aufzeichnen.

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

Wenn Sie ExerciseClient verwenden, muss Ihre App die erforderlichen Berechtigungen anfordern und beibehalten. Wenn Ihre App LOCATION-Daten verwendet, muss sie auch die entsprechenden Berechtigungen dafür anfordern und beibehalten.

Gehen Sie für alle Datentypen vor dem Aufrufen von prepareExercise() oder startExercise() so vor:

  • Geben Sie in der Datei AndroidManifest.xml 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, z. B. GPS oder Herzfrequenz, benötigen möglicherweise etwas Zeit, um sich aufzuwärmen. Außerdem möchten Nutzer ihre Daten möglicherweise sehen, bevor sie mit dem Training beginnen. Mit der optionalen Methode prepareExerciseAsync() können sich diese Sensoren aufwärmen 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:

  • Überprüfen Sie die plattformweite Standorteinstellung. Der Nutzer steuert diese Einstellung im Hauptmenü „Einstellungen“. Sie unterscheidet sich von der Berechtigungsprüfung auf App-Ebene.

    Wenn die Einstellung deaktiviert ist, benachrichtigen Sie den Nutzer, dass er den Zugriff auf den Standort verweigert hat, und fordern Sie ihn auf, ihn zu aktivieren, wenn Ihre App den Standort benötigt.

  • Prüfe, ob deine App Laufzeitberechtigungen für Körpersensoren (API-Level 35 oder niedriger) oder Herzfrequenz (API-Level 36 oder höher), Aktivitätserkennung und genauen Standort hat. Fordern Sie den Nutzer bei fehlenden Berechtigungen zur Laufzeit auf, die Berechtigungen zu erteilen, und geben Sie dabei ausreichend 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 Berechtigungen für Körpersensoren (Herzfrequenz auf API-Ebene 36+) noch Standortberechtigungen erteilt wurden, rufen Sie prepareExerciseAsync() nicht auf, da der Vorbereitungsaufruf speziell dazu dient, vor Beginn eines Trainings eine stabile Herzfrequenz oder einen GPS-Fix zu erhalten. Die App kann weiterhin schrittbasierte Distanz, Tempo, Geschwindigkeit und andere Messwerte abrufen, für die diese Berechtigungen nicht erforderlich sind.

So prüfen Sie, ob Ihr Aufruf von prepareExerciseAsync() erfolgreich sein kann:

  • Verwenden Sie AmbientLifecycleObserver für die Aktivität vor dem Training, die den Vorbereitungsaufruf enthält.
  • Rufen Sie prepareExerciseAsync() über Ihren Dienst im Vordergrund auf. Wenn sie nicht in einem Dienst enthalten ist und an den Aktivitätslebenszyklus gebunden ist, wird die Sensorvorbereitung möglicherweise unnötig beendet.
  • Rufen Sie endExercise() auf, um die Sensoren zu deaktivieren und den Stromverbrauch 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 Aktualisierungen der Sensorverfügbarkeit in ExerciseUpdateCallback über onAvailabilityChanged() bereitgestellt. Diese Informationen können dann dem Nutzer präsentiert werden, damit er entscheiden kann, ob er mit dem Training beginnen möchte.

Training starten

Wenn Sie ein Training starten möchten, erstellen Sie ein ExerciseConfig, um den Trainingstyp, die Datentypen, für die Sie Messwerte erhalten möchten, und alle Trainingsziele 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 Distanz läuft. Du kannst auch einen Trainingsmeilenstein festlegen. Trainingsmeilensteine können mehrmals ausgelöst werden, z. B. jedes Mal, wenn der Nutzer einen bestimmten Punkt nach der festgelegten Distanz erreicht.

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()
}

Du kannst auch für alle Trainingsarten Runden markieren. Health Services bietet ein ExerciseLapSummary mit Messwerten, die über den Rundenzeitraum hinweg aggregiert werden.

Im vorherigen Beispiel wird die Verwendung von isGpsEnabled gezeigt, die beim Anfordern von Standortdaten „true“ sein muss. Die Verwendung von GPS kann jedoch auch bei anderen Messwerten hilfreich sein. Wenn ExerciseConfig die Entfernung als DataType angibt, wird standardmäßig die Entfernung anhand von Schritten geschätzt. Wenn Sie GPS aktivieren, können Standortinformationen verwendet werden, um die Entfernung zu schätzen.

Workouts pausieren, fortsetzen und beenden

Du kannst Trainingseinheiten mit der entsprechenden Methode pausieren, fortsetzen und beenden, z. B. mit pauseExerciseAsync() oder endExerciseAsync().

Verwenden Sie den Status aus ExerciseUpdate als „Source of Truth“. Das Training gilt nicht als pausiert, wenn der Aufruf von pauseExerciseAsync() zurückgegeben wird, sondern erst, wenn dieser Status in der ExerciseUpdate-Nachricht angezeigt wird. Das ist besonders wichtig bei der Gestaltung von UI-Zuständen. Wenn der Nutzer auf „Pausieren“ drückt, deaktiviere die Schaltfläche „Pausieren“ und rufe pauseExerciseAsync() in Health Services auf. Warten Sie, bis Health Services den pausierten Status erreicht hat (ExerciseUpdate.exerciseStateInfo.state), und schalten Sie dann die Schaltfläche um, um die Pausierung aufzuheben. Das liegt daran, dass es länger dauern kann, bis Statusaktualisierungen von Health Services empfangen werden, als bis ein Tastendruck erfolgt. Wenn Sie also alle Änderungen der Benutzeroberfläche an Tastendrücke binden, kann die Benutzeroberfläche mit dem Status von Health Services nicht mehr synchronisiert werden.

Beachten Sie dies in den folgenden Situationen:

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

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

  • Speichere den Status des unvollständigen Trainings, damit der Fortschritt des Nutzers nicht gelöscht wird.
  • Entferne das Symbol für laufende Aktivitäten und sende dem Nutzer eine Benachrichtigung, dass sein Training von einer anderen App beendet wurde.

Berücksichtige auch den Fall, in dem Berechtigungen während eines laufenden Trainings widerrufen werden. Dies wird mit dem Status isEnded und einem ExerciseEndReason von AUTO_END_PERMISSION_LOST gesendet. Gehen Sie in diesem Fall ähnlich wie beim Beenden vor: Speichern Sie den partiellen Status, entfernen Sie das Symbol für laufende Aktivitäten und senden Sie dem Nutzer eine Benachrichtigung darüber, was passiert ist.

Das folgende Beispiel zeigt, 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
        }
        ...
    }
    ...
}

Aktive Dauer verwalten

Während eines Trainings kann eine App die aktive Dauer des Trainings anzeigen. Die App, Health Services und die MCU (Micro Controller Unit) des Geräts – der stromsparende Prozessor, der für die Aufzeichnung von Trainingseinheiten zuständig ist – müssen alle synchronisiert sein und dieselbe aktuelle aktive Dauer haben. Um dies zu ermöglichen, sendet Health Services einen ActiveDurationCheckpoint, der einen Ankerpunkt für den Start des Timers der App bietet.

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

  • activeDuration: wie lange das Training schon aktiv ist
  • time: Zeitpunkt, zu dem die aktive Dauer berechnet wurde

Daher kann die aktive Dauer eines Trainings in der App aus ActiveDurationCheckpoint mit der folgenden Gleichung berechnet werden:

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

So wird der kleine Unterschied zwischen der Berechnung der aktiven Dauer auf der MCU und dem Eintreffen in der App berücksichtigt. Diese kann verwendet werden, um ein Chronometer in der App zu initialisieren und dafür zu sorgen, dass der Timer der App perfekt mit der Zeit in Health Services und der MCU übereinstimmt.

Wenn das Training pausiert wird, wartet die App mit dem Neustart des Timers in der Benutzeroberfläche, bis die berechnete Zeit die in der Benutzeroberfläche angezeigte Zeit überschritten hat. Das liegt daran, dass das Pausensignal 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 bereitgestellt.

Der Prozessor liefert Nachrichten nur, wenn er aktiv ist oder wenn ein maximaler Meldezeitraum erreicht ist, z. B. alle 150 Sekunden. Verlassen Sie sich nicht auf die ExerciseUpdate-Häufigkeit, um einen Chronometer mit der activeDuration voranzutreiben. Ein Beispiel für die Implementierung eines unabhängigen Chronometers finden Sie im Trainingsbeispiel auf GitHub.

Wenn ein Nutzer ein Training startet, können ExerciseUpdate-Nachrichten häufig gesendet werden, z. B. jede Sekunde. Wenn der Nutzer mit dem Training beginnt, kann sich das Display ausschalten. Health Services kann dann Daten seltener, aber weiterhin mit derselben Häufigkeit liefern, um den Hauptprozessor nicht zu aktivieren. Wenn der Nutzer auf den Bildschirm schaut, werden alle Daten, die gerade gebündelt werden, sofort an Ihre App gesendet.

Batching-Rate steuern

In einigen Fällen möchten Sie möglicherweise die Häufigkeit steuern, mit der Ihre App bestimmte Datentypen empfängt, während der Bildschirm ausgeschaltet ist. Mit einem BatchingMode-Objekt kann Ihre App das Standardverhalten für das Batching überschreiben, um Daten häufiger zu erhalten.

So konfigurieren Sie die Batching-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 ein bestimmtes 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 können Sie BatchingMode während des Trainings dynamisch konfigurieren, anstatt ein bestimmtes Batching-Verhalten für die gesamte 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 ein leeres Set an exerciseClient.overrideBatchingModesForActiveExercise().

Zeitstempel

Der Zeitpunkt jedes Datenpunkts gibt die Dauer seit dem Start des Geräts an. So wandeln Sie das in einen Zeitstempel um:

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

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

Korrektheit der Daten

Einige Datentypen können Genauigkeitsinformationen für jeden Datenpunkt enthalten. Dies wird in der Property accuracy dargestellt.

Die Klassen HrAccuracy und LocationAccuracy können für die Datentypen HEART_RATE_BPM bzw. LOCATION ausgefüllt werden. Verwenden Sie, sofern vorhanden, das Attribut accuracy, um zu ermitteln, ob jeder Datenpunkt für Ihre Anwendung ausreichend genau ist.

Daten speichern und hochladen

Verwenden Sie Room, um Daten zu speichern, die von Health Services bereitgestellt werden. Der Daten-Upload erfolgt am Ende des Trainings über einen Mechanismus wie Work Manager. So lässt sich überprüfen, ob Netzwerkaufrufe zum Hochladen von Daten bis zum Ende des Trainings aufgeschoben werden. Dadurch wird der Stromverbrauch während des Trainings minimiert und die Arbeit vereinfacht.

Liste zur Überprüfung der Einbindung

Bevor Sie Ihre App veröffentlichen, in der ExerciseClient von Health Services verwendet wird, sollten Sie die folgende Checkliste durchgehen, um sicherzustellen, dass die Nutzerfreundlichkeit nicht durch häufige Probleme beeinträchtigt wird. Sind die folgenden Voraussetzungen erfüllt?

  • Ihre App prüft die Funktionen der Trainingsart und die Funktionen des Geräts bei jeder Ausführung der App. So können Sie erkennen, wenn ein bestimmtes Gerät oder Training einen der Datentypen, die Ihre App benötigt, nicht unterstützt.
  • Sie fordern die erforderlichen Berechtigungen an und geben sie in Ihrer Manifestdatei an. Bevor prepareExerciseAsync() aufgerufen wird, prüft Ihre App, ob die Laufzeitberechtigungen erteilt wurden.
  • Ihre App verwendet getCurrentExerciseInfoAsync(), um die folgenden Fälle zu verarbeiten:
    • Ein Training wird bereits aufgezeichnet und Ihre App überschreibt das vorherige Training.
    • Eine andere App hat dein Training beendet. Das kann passieren, wenn der Nutzer die App wieder öffnet. Er erhält dann eine Meldung, in der erklärt wird, dass das Training beendet wurde, weil eine andere App die Kontrolle übernommen hat.
  • Wenn Sie LOCATION-Daten verwenden:
    • Ihre App stellt während des gesamten Trainings (einschließlich des Vorbereitungsaufrufs) eine ForegroundService mit dem entsprechenden foregroundServiceType aufrecht.
    • Prüft, ob GPS auf dem Gerät aktiviert ist, und fordert den Nutzer bei Bedarf auf, die Standorteinstellungen zu öffnen.isProviderEnabled(LocationManager.GPS_PROVIDER)
    • Für anspruchsvolle Anwendungsfälle, bei denen der Empfang von Standortdaten mit geringer Latenz von großer Bedeutung ist, sollten Sie den Fused Location Provider (FLP) einbinden und seine Daten als erste Standortbestimmung verwenden. Wenn stabilere Standortinformationen von Health Services verfügbar sind, verwenden Sie diese anstelle von FLP.
  • Wenn für Ihre App Daten hochgeladen werden müssen, werden alle Netzwerkaufrufe zum Hochladen von Daten bis zum Ende des Trainings verzögert. Andernfalls führt Ihre App während der Übung nur sparsam die erforderlichen Netzwerkaufrufe aus.