Rejestrowanie ćwiczenia w Ćwiczeniem klienta

Usługi związane ze zdrowiem zapewniają obsługę aplikacji do ćwiczeń za pomocą ExerciseClient. Dzięki ExerciseClient aplikacja może kontrolować, kiedy ćwiczenie jest w toku, dodawać cele ćwiczeń i otrzymywać aktualizacje dotyczące stanu ćwiczenia, zdarzeń związanych z ćwiczeniami lub innych danych. Więcej informacji znajdziesz na pełnej liście rodzajów ćwiczeń obsługiwanych przez Usługi dotyczące zdrowia.

Zobacz przykładowe ćwiczenie w GitHubie.

Dodawanie zależności

Aby dodać zależność od Usług zdrowotnych, musisz dodać do projektu repozytorium Google Maven. Więcej informacji znajdziesz w repozytorium Maven Google.

Następnie w pliku build.gradle na poziomie modułu dodaj tę zależność:

Groovy

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

Kotlin

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

Struktura aplikacji

Podczas tworzenia aplikacji do ćwiczeń z użyciem Usług zdrowotnych używaj tej struktury:

Podczas przygotowywania się do treningu i w jego trakcie aktywność może zostać przerwana z różnych powodów. Użytkownik może przełączyć się na inną aplikację lub wrócić do tarczy zegarka. System może wyświetlić coś na wierzchu Twojej aktywności lub ekran może się wyłączyć po okresie bezczynności. Używaj stale działającego ForegroundService w połączeniu z ExerciseClient, aby zapewnić prawidłowe działanie przez cały trening.

Użycie ForegroundService umożliwia korzystanie z interfejsu Ongoing Activity API do wyświetlania wskaźnika na tarczach zegarka, dzięki czemu użytkownik może szybko wrócić do treningu.

Konieczne jest prawidłowe żądanie danych o lokalizacji w usłudze działającej na pierwszym planie. W pliku manifestu określ niezbędne typy usług na pierwszym planieuprawnienia:

<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>

Użyj AmbientLifecycleObserver w przypadku aktywności przed treningiem, która zawiera wywołanie prepareExercise(), oraz w przypadku aktywności podczas treningu. Nie aktualizuj jednak wyświetlacza podczas treningu w trybie otoczenia: usługi Zdrowie grupują dane treningu, gdy ekran urządzenia jest w trybie otoczenia, aby oszczędzać energię, więc wyświetlane informacje mogą nie być aktualne. Podczas treningów wyświetlaj dane, które są przydatne dla użytkownika, pokazując aktualne informacje lub pusty ekran.

Sprawdzanie możliwości

Każdy ExerciseType obsługuje określone typy danych dotyczące danych i celów związanych z aktywnością fizyczną. Sprawdź te możliwości przy uruchamianiu, ponieważ mogą się one różnić w zależności od urządzenia. Urządzenie może nie obsługiwać określonego rodzaju ćwiczeń lub konkretnej funkcji, np. automatycznego wstrzymywania. Dodatkowo możliwości urządzenia mogą się z czasem zmieniać, np. po aktualizacji oprogramowania.

Podczas uruchamiania aplikacji wysyłaj zapytania o możliwości urządzenia oraz przechowuj i przetwarzaj te informacje:

  • ćwiczenia obsługiwane przez platformę;
  • funkcje obsługiwane w przypadku poszczególnych ćwiczeń;
  • Typy danych obsługiwane w przypadku poszczególnych ćwiczeń.
  • uprawnienia wymagane w przypadku każdego z tych typów danych;

Używaj urządzenia ExerciseCapabilities.getExerciseTypeCapabilities() z wybranym typem ćwiczeń, aby sprawdzić, o jakie dane możesz poprosić, jakie cele ćwiczeń możesz skonfigurować i jakie inne funkcje są dostępne w przypadku tego typu. Pokazuje to poniższy przykład:

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

W zwróconej liście ExerciseTypeCapabilities, supportedDataTypes znajdują się typy danych, o które możesz poprosić. Różni się to w zależności od urządzenia, więc uważaj, aby nie prosić o DataType, które nie jest obsługiwane. W przeciwnym razie Twoja prośba może się nie powieść.

W polach supportedGoalssupportedMilestones określ, czy ćwiczenie może obsługiwać cel ćwiczenia, który chcesz utworzyć.

Jeśli aplikacja umożliwia użytkownikowi korzystanie z automatycznego wstrzymywania, musisz sprawdzić, czy ta funkcja jest obsługiwana przez urządzenie, używając supportsAutoPauseAndResume. ExerciseClient odrzuca żądania, które nie są obsługiwane na urządzeniu.

W tym przykładzie sprawdzamy obsługę typu danych HEART_RATE_BPM, funkcję celu STEPS_TOTAL i funkcję automatycznego wstrzymywania:

// 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

Rejestrowanie aktualizacji stanu ćwiczeń

Aktualizacje ćwiczeń są dostarczane do słuchacza. Aplikacja może zarejestrować tylko jednego odbiorcę naraz. Skonfiguruj odbiornik przed rozpoczęciem treningu, jak pokazano w poniższym przykładzie. Odbiorca otrzymuje tylko aktualizacje dotyczące ćwiczeń, których właścicielem jest Twoja aplikacja.

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)

Zarządzanie czasem trwania ćwiczenia

Usługi związane ze zdrowiem obsługują co najwyżej 1 ćwiczenie naraz we wszystkich aplikacjach na urządzeniu. Jeśli śledzone jest ćwiczenie, a inna aplikacja zacznie śledzić nowe ćwiczenie, pierwsze ćwiczenie zostanie zakończone.

Zanim zaczniesz ćwiczyć, wykonaj te czynności:

  • Sprawdź, czy ćwiczenie jest już śledzone, i odpowiednio zareaguj. Na przykład poproś użytkownika o potwierdzenie przed zastąpieniem poprzedniego ćwiczenia i rozpoczęciem śledzenia nowego.

Poniższy przykład pokazuje, jak sprawdzić, czy istnieje ćwiczenie z wywołaniem getCurrentExerciseInfoAsync:

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.
    }
}

Uprawnienia

Podczas korzystania z ExerciseClient upewnij się, że Twoja aplikacja prosi o niezbędne uprawnienia i je utrzymuje. Jeśli Twoja aplikacja korzysta z danych LOCATION, upewnij się, że żąda odpowiednich uprawnień i je utrzymuje.

W przypadku wszystkich typów danych przed wywołaniem funkcji prepareExercise() lub startExercise() wykonaj te czynności:

  • W pliku AndroidManifest.xml określ odpowiednie uprawnienia dla żądanych typów danych.
  • Sprawdź, czy użytkownik przyznał niezbędne uprawnienia. Więcej informacji znajdziesz w artykule Prośby o przyznanie uprawnień aplikacji. Usługi związane ze zdrowiem odrzucają żądanie, jeśli niezbędne uprawnienia nie zostały jeszcze przyznane.

W przypadku danych o lokalizacji wykonaj te dodatkowe czynności:

Przygotowanie do treningu

Niektóre czujniki, np. GPS lub czujnik tętna, mogą potrzebować trochę czasu na rozgrzanie się, a użytkownik może chcieć zobaczyć dane przed rozpoczęciem treningu. Opcjonalna metoda prepareExerciseAsync() umożliwia rozgrzanie tych czujników i otrzymywanie danych bez włączania timera treningu. Ten czas przygotowania nie ma wpływu na activeDuration.

Zanim zadzwonisz pod numer prepareExerciseAsync(), sprawdź te kwestie:

  • Sprawdź ustawienie lokalizacji na poziomie platformy. Użytkownik kontroluje to ustawienie w głównym menu Ustawienia. Różni się ono od sprawdzania uprawnień na poziomie aplikacji.

    Jeśli to ustawienie jest wyłączone, powiadom użytkownika, że odmówił dostępu do lokalizacji, i poproś go o włączenie tej funkcji, jeśli jest ona wymagana przez Twoją aplikację.

  • Sprawdź, czy aplikacja ma uprawnienia do czujników na ciele (API na poziomie 35 lub niższym) lub do pomiaru tętna (API na poziomie 36 lub wyższym), rozpoznawania aktywności i dokładnej lokalizacji. W przypadku brakujących uprawnień poproś użytkownika o przyznanie uprawnień w czasie działania, podając odpowiedni kontekst. Jeśli użytkownik nie przyzna określonego uprawnienia, usuń z wywołania funkcji prepareExerciseAsync() typy danych powiązane z tym uprawnieniem. Jeśli nie przyznano uprawnień do czujników na ciele (tętno na poziomie interfejsu API 36 lub wyższym) ani uprawnień do lokalizacji, nie wywołuj funkcji prepareExerciseAsync(), ponieważ wywołanie prepare służy do uzyskania stabilnego tętna lub stałej lokalizacji GPS przed rozpoczęciem ćwiczenia. Aplikacja nadal może uzyskiwać dane o dystansie, tempie, prędkości i innych wskaźnikach, które nie wymagają tych uprawnień.

Aby sprawdzić, czy wywołanie funkcji prepareExerciseAsync() może się powieść:

  • Użyj AmbientLifecycleObserver w przypadku aktywności przed treningiem, która zawiera wywołanie przygotowania.
  • Wywołaj prepareExerciseAsync() z usługi działającej na pierwszym planie. Jeśli nie jest ona częścią usługi i jest powiązana z cyklem życia aktywności, przygotowanie czujnika może zostać niepotrzebnie zakończone.
  • Wywołaj endExercise(), aby wyłączyć czujniki i zmniejszyć zużycie energii, jeśli użytkownik opuści aktywność przed treningiem.

Poniższy przykład pokazuje, jak wywołać funkcję prepareExerciseAsync():

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.

Gdy aplikacja jest w stanie PREPARING, aktualizacje dostępności czujników są dostarczane w stanie ExerciseUpdateCallback przez onAvailabilityChanged(). Te informacje mogą być następnie wyświetlane użytkownikowi, aby mógł zdecydować, czy rozpocząć trening.

Rozpocznij trening

Gdy chcesz rozpocząć ćwiczenie, utwórz ExerciseConfig, aby skonfigurować typ ćwiczenia, typy danych, dla których chcesz otrzymywać dane, oraz cele lub kamienie milowe ćwiczenia.

Cele ćwiczeń składają się z DataType i warunku. Cele ćwiczeń to jednorazowe cele, które są wywoływane po spełnieniu warunku, np. gdy użytkownik przebiegnie określony dystans. Możesz też ustawić kamień milowy związany z ćwiczeniami. Osiągnięcia związane z ćwiczeniami mogą być wywoływane wielokrotnie, np. za każdym razem, gdy użytkownik przebiegnie określony punkt za wyznaczonym dystansem.

Poniższy przykład pokazuje, jak utworzyć po jednym celu każdego typu:

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

Możesz też oznaczać okrążenia we wszystkich ćwiczeniach. Usługi dotyczące zdrowia udostępniają ExerciseLapSummary ze wskaźnikami zagregowanymi w okresie okrążenia.

W poprzednim przykładzie pokazano użycie wartości isGpsEnabled, która musi być prawdziwa, gdy wysyłane jest żądanie danych o lokalizacji. Korzystanie z GPS może jednak pomóc w określaniu innych danych. Jeśli ExerciseConfig określa dystans jako DataType, domyślnie do szacowania dystansu używane są kroki. Opcjonalnie możesz włączyć GPS, aby do szacowania odległości używać informacji o lokalizacji.

Wstrzymywanie, wznawianie i kończenie treningu

Treningi możesz wstrzymywać, wznawiać i kończyć za pomocą odpowiedniej metody, np. pauseExerciseAsync() lub endExerciseAsync().

Użyj stanu z ExerciseUpdate jako źródła informacji. Trening nie jest uznawany za wstrzymany, gdy zwracana jest wartość wywołania pauseExerciseAsync(), ale gdy ten stan jest odzwierciedlony w wiadomości ExerciseUpdate. Jest to szczególnie ważne w przypadku stanów interfejsu. Jeśli użytkownik naciśnie przycisk wstrzymania, wyłącz go i wywołaj funkcję pauseExerciseAsync() w usługach zdrowotnych. Poczekaj, aż Usługi zdrowotne osiągną stan wstrzymania, korzystając z ExerciseUpdate.exerciseStateInfo.state, a następnie przełącz przycisk, aby wznowić działanie. Dzieje się tak, ponieważ aktualizacje stanu Usług zdrowotnych mogą być dostarczane dłużej niż naciśnięcie przycisku. Jeśli powiążesz wszystkie zmiany interfejsu z naciśnięciami przycisków, interfejs może się rozsynchronizować ze stanem Usług zdrowotnych.

Pamiętaj o tym w tych sytuacjach:

  • Automatyczne wstrzymywanie jest włączone: trening może się wstrzymać lub rozpocząć bez interakcji użytkownika.
  • Inna aplikacja rozpoczyna trening: trening może zostać zakończony bez interakcji użytkownika.

Jeśli trening w aplikacji zostanie zakończony przez inną aplikację, musi ona prawidłowo obsłużyć to zakończenie:

  • Zapisz stan częściowego treningu, aby nie utracić postępów użytkownika.
  • Usuń ikonę trwającej aktywności i wyślij użytkownikowi powiadomienie z informacją, że trening został zakończony przez inną aplikację.

Obsługuj też sytuację, w której uprawnienia zostaną cofnięte podczas trwającego ćwiczenia. Jest on wysyłany w stanie isEnded z wartością ExerciseEndReason AUTO_END_PERMISSION_LOST. W tym przypadku postępuj podobnie jak w przypadku zakończenia: zapisz częściowy stan, usuń ikonę trwającej aktywności i wyślij użytkownikowi powiadomienie o tym, co się stało.

Poniższy przykład pokazuje, jak prawidłowo sprawdzić, czy nastąpiło zakończenie:

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
        }
        ...
    }
    ...
}

Zarządzanie czasem aktywności

Podczas ćwiczeń aplikacja może wyświetlać czas trwania aktywności. Aplikacja, Usługi zdrowotne i mikrokontroler urządzenia (MCU) – energooszczędny procesor odpowiedzialny za śledzenie ćwiczeń – muszą być zsynchronizowane i mieć ten sam bieżący czas trwania aktywności. Aby ułatwić zarządzanie tym procesem, Usługi zdrowotne wysyłają ActiveDurationCheckpoint, który stanowi punkt odniesienia, od którego aplikacja może rozpocząć odliczanie czasu.

Ponieważ czas aktywności jest wysyłany z mikrokontrolera i może minąć trochę czasu, zanim dotrze do aplikacji, obiekt ActiveDurationCheckpoint zawiera 2 właściwości:

  • activeDuration: czas trwania ćwiczenia
  • time: kiedy obliczono czas aktywności.

Dlatego w aplikacji aktywny czas trwania ćwiczenia można obliczyć na podstawie wartości ActiveDurationCheckpoint za pomocą tego równania:

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

Uwzględnia to niewielką różnicę między czasem trwania aktywności obliczanym na mikrokontrolerze a czasem trwania aktywności docierającym do aplikacji. Można go użyć do zainicjowania chronometru w aplikacji i zapewnienia, że timer aplikacji jest idealnie zsynchronizowany z czasem w Usługach zdrowotnych i na mikrokontrolerze.

Jeśli ćwiczenie zostanie wstrzymane, aplikacja poczeka z ponownym uruchomieniem timera w interfejsie, aż obliczony czas przekroczy czas wyświetlany w interfejsie. Dzieje się tak, ponieważ sygnał wstrzymania dociera do usług zdrowotnych i mikrokontrolera z niewielkim opóźnieniem. Jeśli na przykład aplikacja jest wstrzymana w momencie t=10 sekund, Usługi zdrowotne mogą nie przekazać aplikacji aktualizacji PAUSED do momentu t=10, 2 sekundy.

Praca z danymi z interfejsu ExerciseClient

Dane dotyczące typów danych, dla których zarejestrowana jest Twoja aplikacja, są dostarczane w wiadomościach ExerciseUpdate.

Procesor dostarcza wiadomości tylko wtedy, gdy jest aktywny lub gdy osiągnięty zostanie maksymalny okres raportowania, np. co 150 sekund. Nie polegaj na ExerciseUpdate częstotliwości, aby przesuwać chronometr za pomocą activeDuration. Przykład implementacji niezależnego chronometru znajdziesz w przykładowym ćwiczeniu w GitHubie.

Gdy użytkownik rozpocznie trening, ExerciseUpdate wiadomości mogą być dostarczane często, np. co sekundę. Gdy użytkownik rozpocznie trening, ekran może się wyłączyć. Usługi zdrowotne mogą wtedy rzadziej dostarczać dane, ale nadal będą próbkowane z tą samą częstotliwością, aby uniknąć wybudzania głównego procesora. Gdy użytkownik patrzy na ekran, wszystkie dane, które są w trakcie przetwarzania wsadowego, są natychmiast dostarczane do aplikacji.

Kontrolowanie szybkości przetwarzania zbiorczego

W niektórych przypadkach możesz chcieć kontrolować częstotliwość, z jaką aplikacja otrzymuje określone typy danych, gdy ekran jest wyłączony. Obiekt BatchingMode umożliwia aplikacji zastąpienie domyślnego zachowania związanego z grupowaniem, aby częściej otrzymywać dane.

Aby skonfigurować szybkość przetwarzania wsadowego, wykonaj te czynności:

  1. Sprawdź, czy urządzenie obsługuje daną BatchingMode definicję:

    // 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. Określ, że obiekt ExerciseConfig ma używać konkretnego elementu BatchingMode, jak pokazano w tym fragmencie kodu.

    val config = ExerciseConfig(
        exerciseType = ExerciseType.WORKOUT,
        dataTypes = setOf(
            DataType.HEART_RATE_BPM,
            DataType.TOTAL_CALORIES
        ),
        // ...
        batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    )
    
  3. Opcjonalnie możesz dynamicznie konfigurować BatchingMode podczas treningu, zamiast utrzymywać określone zachowanie grupowania przez cały czas trwania treningu:

    val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
    
  4. Aby wyczyścić dostosowany zbiór BatchingMode i przywrócić domyślne działanie, przekaż pusty zbiór do funkcji exerciseClient.overrideBatchingModesForActiveExercise().

Sygnatury czasowe

Punkt w czasie każdego punktu danych reprezentuje czas od uruchomienia urządzenia. Aby przekonwertować go na sygnaturę czasową:

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

Tej wartości można następnie użyć z parametrem getStartInstant() lub getEndInstant() dla każdego punktu danych.

Dokładność danych

Niektóre typy danych mogą mieć informacje o dokładności powiązane z każdym punktem danych. Jest to reprezentowane przez właściwość accuracy.

Klasy HrAccuracy i LocationAccuracy można wypełniać odpowiednio typami danych HEART_RATE_BPM i LOCATION. Jeśli jest dostępna, użyj właściwości accuracy, aby określić, czy każdy punkt danych ma wystarczającą dokładność dla Twojej aplikacji.

Przechowywanie i przesyłanie danych

Użyj Room, aby utrwalać dane dostarczane przez Health Services. Przesyłanie danych następuje na końcu ćwiczenia za pomocą mechanizmu takiego jak Work Manager. Pomaga to sprawdzić, czy wywołania sieciowe służące do przesyłania danych są odraczane do czasu zakończenia ćwiczenia, co minimalizuje zużycie energii podczas ćwiczenia i upraszcza pracę.

Lista kontrolna integracji

Przed opublikowaniem aplikacji korzystającej z ExerciseClient Usług zdrowotnych zapoznaj się z tą listą kontrolną, aby sprawdzić, czy w przypadku użytkowników nie występują typowe problemy. Upewnij się, że:

  • Aplikacja sprawdza możliwości rodzaju ćwiczenia i urządzenia za każdym razem, gdy jest uruchamiana. Dzięki temu możesz wykryć, kiedy dane urządzenie lub ćwiczenie nie obsługuje jednego z rodzajów danych, których potrzebuje Twoja aplikacja.
  • Musisz poprosić o niezbędne uprawnienia i je zachować, a także określić je w pliku manifestu. Przed wywołaniem funkcji prepareExerciseAsync() aplikacja sprawdza, czy przyznano uprawnienia w czasie działania.
  • Aplikacja używa getCurrentExerciseInfoAsync() do obsługi przypadków, w których:
    • Ćwiczenie jest już śledzone, a aplikacja zastępuje poprzednie ćwiczenie.
    • Inna aplikacja zakończyła ćwiczenie. Może się to zdarzyć, gdy użytkownik ponownie otworzy aplikację i zobaczy komunikat z informacją, że ćwiczenie zostało przerwane, ponieważ inna aplikacja przejęła kontrolę.
  • Jeśli używasz danych LOCATION:
    • Aplikacja utrzymuje ForegroundService z odpowiednim foregroundServiceType przez cały czas trwania ćwiczenia (w tym podczas przygotowania do połączenia).
    • Sprawdza, czy na urządzeniu jest włączony GPS, i w razie potrzeby wyświetla użytkownikowi prośbę o otwarcie ustawień lokalizacji.isProviderEnabled(LocationManager.GPS_PROVIDER)
    • W przypadku wymagających zastosowań, w których otrzymywanie danych o lokalizacji z niskim opóźnieniem ma duże znaczenie, rozważ zintegrowanie usługi lokalizacji zintegrowanej (FLP) i używanie jej danych jako początkowego określenia lokalizacji. Gdy Usługi zdrowotne udostępnią bardziej stabilne informacje o lokalizacji, używaj ich zamiast FLP.
  • Jeśli Twoja aplikacja wymaga przesyłania danych, wszystkie wywołania sieciowe służące do przesyłania danych są odraczane do czasu zakończenia ćwiczenia. W przeciwnym razie aplikacja będzie w trakcie ćwiczenia oszczędnie wykonywać niezbędne wywołania sieciowe.