ExerciseClient का इस्तेमाल करके, किसी कसरत को रिकॉर्ड करें

Health Services, ExerciseClient के ज़रिए कसरत करने वाले ऐप्लिकेशन के लिए सहायता उपलब्ध कराता है. ExerciseClient की मदद से, आपका ऐप्लिकेशन यह कंट्रोल कर सकता है कि कसरत कब शुरू हो रही है. साथ ही, कसरत के लक्ष्य जोड़े जा सकते हैं. इसके अलावा, कसरत की स्थिति, कसरत के इवेंट या अन्य मेट्रिक के बारे में अपडेट पाए जा सकते हैं. ज़्यादा जानकारी के लिए, एक्सरसाइज़ के उन टाइप की पूरी सूची देखें जिनके साथ Health Services काम करती है.

GitHub पर एक्सरसाइज़ का सैंपल देखें.

डिपेंडेंसी जोड़ें

Health Services पर डिपेंडेंसी जोड़ने के लिए, आपको अपने प्रोजेक्ट में Google Maven रिपॉज़िटरी जोड़नी होगी. ज़्यादा जानकारी के लिए, Google की Maven रिपॉज़िटरी देखें.

इसके बाद, मॉड्यूल-लेवल की build.gradle फ़ाइल में, यह डिपेंडेंसी जोड़ें:

ग्रूवी

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

Kotlin

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

ऐप्लिकेशन का स्ट्रक्चर

Health Services की मदद से कसरत से जुड़ा ऐप्लिकेशन बनाते समय, ऐप्लिकेशन के इस स्ट्रक्चर का इस्तेमाल करें:

  • अपनी स्क्रीन और नेविगेशन को मुख्य गतिविधि के अंदर रखें.
  • कसरत की स्थिति, सेंसर डेटा, जारी गतिविधि, और डेटा को फ़ोरग्राउंड सेवा की मदद से मैनेज करें.
  • Room की मदद से डेटा सेव करें और WorkManager का इस्तेमाल करके डेटा अपलोड करें.

कसरत की तैयारी करते समय और कसरत के दौरान, आपकी गतिविधि कई वजहों से रुक सकती है. उपयोगकर्ता किसी दूसरे ऐप्लिकेशन पर स्विच कर सकता है या स्मार्टवॉच की होम स्क्रीन पर वापस जा सकता है. ऐसा हो सकता है कि सिस्टम आपकी गतिविधि के ऊपर कुछ दिखाए या कुछ समय तक कोई गतिविधि न होने पर स्क्रीन बंद हो जाए. पूरी कसरत के दौरान सही तरीके से काम करने के लिए, ExerciseClient के साथ लगातार चलने वाले ForegroundService का इस्तेमाल करें.

ForegroundService का इस्तेमाल करके, Ongoing Activity API का इस्तेमाल किया जा सकता है. इससे, स्मार्टवॉच की स्क्रीन पर एक इंडिकेटर दिखाया जा सकता है. इससे उपयोगकर्ता, कसरत पर तुरंत वापस जा सकता है.

यह ज़रूरी है कि फ़ोरग्राउंड सेवा में, जगह की जानकारी के डेटा का अनुरोध सही तरीके से किया जाए. अपनी मेनिफ़ेस्ट फ़ाइल में, ज़रूरी फ़ोरग्राउंड सेवा के टाइप और अनुमतियां बताएं:

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

कसरत से पहले की जाने वाली गतिविधि के लिए, AmbientLifecycleObserver का इस्तेमाल करें. इसमें prepareExercise() कॉल और कसरत से जुड़ी गतिविधि शामिल होती है. हालांकि, कसरत के दौरान डिसप्ले को अपडेट न करें एम्बिएंट मोड के दौरान: ऐसा इसलिए है, क्योंकि हेल्थ सेवाएं, डिवाइस की स्क्रीन के एम्बिएंट मोड में होने पर कसरत के डेटा को बैच करती हैं, ताकि बैटरी बचाई जा सके. इसलिए, हो सकता है कि दिखाई गई जानकारी हाल की न हो. कसरत के दौरान, उपयोगकर्ता को काम का डेटा दिखाएं. इसमें अप-टू-डेट जानकारी या खाली स्क्रीन दिखानी चाहिए.

सुविधाओं के बारे में जानकारी

हर ExerciseType, मेट्रिक और कसरत के लक्ष्यों के लिए कुछ डेटा टाइप के साथ काम करता है. स्टार्टअप के दौरान इन सुविधाओं की जांच करें, क्योंकि ये डिवाइस के हिसाब से अलग-अलग हो सकती हैं. ऐसा हो सकता है कि कोई डिवाइस किसी खास तरह की कसरत के साथ काम न करे. यह भी हो सकता है कि वह किसी खास फ़ंक्शन के साथ काम न करे. जैसे, अपने-आप रुकने की सुविधा. इसके अलावा, किसी डिवाइस की सुविधाएं समय के साथ बदल सकती हैं. जैसे, सॉफ़्टवेयर अपडेट के बाद.

ऐप्लिकेशन के चालू होने पर, डिवाइस की सुविधाओं के बारे में क्वेरी करें. साथ ही, यहां दी गई जानकारी को सेव करें और प्रोसेस करें:

  • ऐसे व्यायाम जो प्लैटफ़ॉर्म पर उपलब्ध हैं.
  • हर कसरत के लिए काम करने वाली सुविधाएं.
  • हर कसरत के लिए इस्तेमाल किए जा सकने वाले डेटा टाइप.
  • उनमें से हर तरह के डेटा के लिए ज़रूरी अनुमतियां.

चुनी गई कसरत के टाइप के साथ ExerciseCapabilities.getExerciseTypeCapabilities() का इस्तेमाल करें. इससे आपको यह पता चलेगा कि किस तरह की मेट्रिक का अनुरोध किया जा सकता है, कसरत के कौनसे लक्ष्य कॉन्फ़िगर किए जा सकते हैं, और उस टाइप के लिए कौनसी अन्य सुविधाएं उपलब्ध हैं. इसे यहां दिए गए उदाहरण में दिखाया गया है:

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

जवाब में मिले ExerciseTypeCapabilities में, supportedDataTypes उन डेटा टाइप की सूची दिखाता है जिनके लिए डेटा का अनुरोध किया जा सकता है. यह सुविधा अलग-अलग डिवाइसों पर अलग-अलग तरीके से काम करती है. इसलिए, ध्यान रखें कि आपने ऐसी DataType का अनुरोध न किया हो जो काम नहीं करती. ऐसा करने पर, हो सकता है कि आपका अनुरोध पूरा न हो.

supportedGoals और supportedMilestones फ़ील्ड का इस्तेमाल करके यह तय करें कि कसरत, आपके तय किए गए लक्ष्य को पूरा करने में मदद कर सकती है या नहीं.

अगर आपका ऐप्लिकेशन, उपयोगकर्ता को अपने-आप रुकने की सुविधा इस्तेमाल करने की अनुमति देता है, तो आपको यह जांच करनी होगी कि यह सुविधा, supportsAutoPauseAndResume का इस्तेमाल करने वाले डिवाइस पर काम करती है या नहीं. ExerciseClient उन अनुरोधों को अस्वीकार करता है जो डिवाइस पर काम नहीं करते.

यहां दिए गए उदाहरण में, HEART_RATE_BPM डेटा टाइप, STEPS_TOTAL लक्ष्य की सुविधा, और अपने-आप रुकने की सुविधा के लिए सहायता की जांच की गई है:

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

व्यायाम की स्थिति से जुड़े अपडेट पाने के लिए रजिस्टर करें

व्यायाम से जुड़े अपडेट, सुनने वाले व्यक्ति को भेजे जाते हैं. आपका ऐप्लिकेशन, एक बार में सिर्फ़ एक लिसनर रजिस्टर कर सकता है. वर्कआउट शुरू करने से पहले, अपना लिसनर सेट अप करें. इसके लिए, यहां दिया गया उदाहरण देखें. लिसनर को सिर्फ़ उन कसरतों के बारे में अपडेट मिलते हैं जिनका मालिकाना हक आपके ऐप्लिकेशन के पास है.

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)

एक्सरसाइज़ के लाइफ़टाइम को मैनेज करना

Health Services, डिवाइस पर मौजूद सभी ऐप्लिकेशन के लिए, एक बार में ज़्यादा से ज़्यादा एक कसरत को सपोर्ट करती है. अगर किसी कसरत को ट्रैक किया जा रहा है और कोई दूसरा ऐप्लिकेशन नई कसरत को ट्रैक करना शुरू कर देता है, तो पहली कसरत बंद हो जाती है.

एक्सरसाइज़ शुरू करने से पहले, ये काम करें:

  • यह देखना कि क्या कोई कसरत पहले से ट्रैक की जा रही है और उसके हिसाब से कार्रवाई करना. उदाहरण के लिए, पिछली कसरत को बदलने और नई कसरत को ट्रैक करना शुरू करने से पहले, उपयोगकर्ता से पुष्टि करने के लिए कहें.

यहां दिए गए उदाहरण में, 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.
    }
}

अनुमतियां

ExerciseClient का इस्तेमाल करते समय, पक्का करें कि आपका ऐप्लिकेशन ज़रूरी अनुमतियों का अनुरोध करता हो और उन्हें बनाए रखता हो. अगर आपका ऐप्लिकेशन LOCATION डेटा का इस्तेमाल करता है, तो पक्का करें कि आपका ऐप्लिकेशन इसके लिए भी सही अनुमतियों का अनुरोध करे और उन्हें बनाए रखे.

सभी डेटा टाइप के लिए, prepareExercise() या startExercise() को कॉल करने से पहले, यह काम करें:

  • अपनी AndroidManifest.xml फ़ाइल में, अनुरोध किए गए डेटा टाइप के लिए सही अनुमतियां तय करें.
  • पुष्टि करें कि उपयोगकर्ता ने ज़रूरी अनुमतियां दी हों. ज़्यादा जानकारी के लिए, ऐप्लिकेशन की अनुमतियों का अनुरोध करना लेख पढ़ें. अगर ज़रूरी अनुमतियां पहले से नहीं दी गई हैं, तो Health Services अनुरोध को अस्वीकार कर देता है.

जगह की जानकारी के डेटा के लिए, ये अतिरिक्त चरण पूरे करें:

  • देखें कि isProviderEnabled(LocationManager.GPS_PROVIDER) का इस्तेमाल करके, डिवाइस पर जीपीएस चालू हो. अगर ज़रूरी हो, तो उपयोगकर्ता को जगह की जानकारी की सेटिंग खोलने के लिए कहें.
  • पक्का करें कि कसरत के दौरान, सही foregroundServiceType के साथ ForegroundService को बनाए रखा गया हो.

कसरत करने की तैयारी करना

कुछ सेंसर, जैसे कि जीपीएस या दिल की धड़कन की दर को काम करने में थोड़ा समय लग सकता है. इसके अलावा, उपयोगकर्ता कसरत शुरू करने से पहले अपना डेटा देखना चाहेगा. वैकल्पिक prepareExerciseAsync() तरीके से, इन सेंसर को चालू होने में समय लगता है. साथ ही, कसरत के लिए टाइमर शुरू किए बिना डेटा मिल जाता है. activeDuration पर, तैयारी के इस समय का कोई असर नहीं पड़ता.

prepareExerciseAsync() को कॉल करने से पहले, इन बातों का ध्यान रखें:

  • पूरे प्लैटफ़ॉर्म के लिए जगह की जानकारी की सेटिंग देखें. उपयोगकर्ता इस सेटिंग को मुख्य सेटिंग मेन्यू में कंट्रोल करता है. यह ऐप्लिकेशन-लेवल की अनुमतियों की जांच से अलग है.

    अगर सेटिंग बंद है, तो उपयोगकर्ता को सूचना दें कि उसने जगह की जानकारी का ऐक्सेस अस्वीकार कर दिया है. साथ ही, अगर आपके ऐप्लिकेशन को जगह की जानकारी की ज़रूरत है, तो उसे चालू करने के लिए कहें.

  • पुष्टि करें कि आपके ऐप्लिकेशन के पास, शरीर के सेंसर (एपीआई लेवल 35 या इससे कम) या दिल की धड़कन (एपीआई लेवल 36 या इससे ज़्यादा), गतिविधि पहचानने, और सटीक जगह की जानकारी के लिए रनटाइम की अनुमतियां हैं. अगर कोई अनुमति मौजूद नहीं है, तो उपयोगकर्ता को रनटाइम की अनुमतियों के लिए प्रॉम्प्ट करें. साथ ही, उसे ज़रूरी जानकारी दें. अगर उपयोगकर्ता किसी अनुमति को स्वीकार नहीं करता है, तो prepareExerciseAsync() को किए गए कॉल से उस अनुमति से जुड़े डेटा टाइप हटा दें. अगर बॉडी सेंसर (एपीआई लेवल 36 या इससे ज़्यादा पर धड़कन की दर) और जगह की जानकारी की अनुमतियां नहीं दी गई हैं, तो prepareExerciseAsync() को कॉल न करें. ऐसा इसलिए, क्योंकि prepare कॉल खास तौर पर कसरत शुरू करने से पहले, धड़कन की दर को स्थिर करने या जीपीएस की जानकारी पाने के लिए किया जाता है. ऐप्लिकेशन को अब भी दूरी, गति, रफ़्तार, और अन्य मेट्रिक का डेटा मिल सकता है. इसके लिए, इन अनुमतियों की ज़रूरत नहीं होती.

इस बात की पुष्टि करने के लिए कि prepareExerciseAsync() को कॉल किया जा सकता है, यह तरीका अपनाएं:

  • AmbientLifecycleObserver का इस्तेमाल, कसरत से पहले की जाने वाली गतिविधि के लिए करें. इसमें तैयारी करने का कॉल शामिल होता है.
  • अपनी फ़ोरग्राउंड सेवा से prepareExerciseAsync() को कॉल करें. अगर यह किसी सेवा में नहीं है और ऐक्टिविटी के लाइफ़साइकल से जुड़ा है, तो सेंसर की तैयारी को बिना किसी वजह के बंद किया जा सकता है.
  • अगर उपयोगकर्ता, कसरत से पहले की गतिविधि से हट जाता है, तो सेंसर बंद करने और बैटरी का इस्तेमाल कम करने के लिए endExercise() को कॉल करें.

यहां दिए गए उदाहरण में, 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.

ऐप्लिकेशन के PREPARING स्थिति में होने पर, सेंसर की उपलब्धता से जुड़े अपडेट, onAvailabilityChanged() के ज़रिए ExerciseUpdateCallback में डिलीवर किए जाते हैं. इसके बाद, यह जानकारी उपयोगकर्ता को दिखाई जा सकती है, ताकि वह यह तय कर सके कि उसे कसरत शुरू करनी है या नहीं.

वर्कआउट शुरू करना

जब आपको कोई कसरत शुरू करनी हो, तब ExerciseConfig बनाएं. इससे कसरत का टाइप, मेट्रिक पाने के लिए डेटा टाइप, और कसरत के लक्ष्य या माइलस्टोन कॉन्फ़िगर किए जा सकते हैं.

कसरत के लक्ष्यों में DataType और शर्त शामिल होती है. कसरत के लक्ष्य, एक बार सेट किए जाने वाले लक्ष्य होते हैं. ये तब ट्रिगर होते हैं, जब कोई शर्त पूरी हो जाती है. जैसे, जब उपयोगकर्ता एक तय दूरी तक दौड़ता है. कसरत का माइलस्टोन भी सेट किया जा सकता है. कसरत के माइलस्टोन को कई बार ट्रिगर किया जा सकता है. जैसे, जब उपयोगकर्ता तय की गई दूरी से ज़्यादा दौड़ता है.

यहां दिए गए सैंपल में, हर टाइप का एक-एक लक्ष्य बनाने का तरीका बताया गया है:

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

सभी कसरतों के लिए लैप भी मार्क किए जा सकते हैं. Health Services, लैप पीरियड के दौरान एग्रीगेट की गई मेट्रिक के साथ ExerciseLapSummary उपलब्ध कराता है.

पिछले उदाहरण में isGpsEnabled के इस्तेमाल के बारे में बताया गया है. जगह की जानकारी का डेटा ऐक्सेस करने का अनुरोध करते समय, यह सही होना चाहिए. हालांकि, जीपीएस का इस्तेमाल करने से अन्य मेट्रिक में भी मदद मिल सकती है. अगर ExerciseConfig में दूरी को DataType के तौर पर दिखाया गया है, तो दूरी का अनुमान लगाने के लिए डिफ़ॉल्ट रूप से कदमों की गिनती का इस्तेमाल किया जाता है. जीपीएस को चालू करने पर, दूरी का अनुमान लगाने के लिए जगह की जानकारी का इस्तेमाल किया जा सकता है. हालांकि, ऐसा करना ज़रूरी नहीं है.

कसरत को रोकना, फिर से शुरू करना, और बंद करना

कसरत को रोकने, फिर से शुरू करने, और खत्म करने के लिए, सही तरीके का इस्तेमाल किया जा सकता है. जैसे, pauseExerciseAsync() या endExerciseAsync().

ExerciseUpdate में मौजूद राज्य को सोर्स ऑफ़ ट्रुथ के तौर पर इस्तेमाल करें. pauseExerciseAsync() को कॉल करने पर, कसरत को रुका हुआ नहीं माना जाता. इसके बजाय, जब pauseExerciseAsync() मैसेज में यह स्थिति दिखती है, तब कसरत को रुका हुआ माना जाता है.ExerciseUpdate यूज़र इंटरफ़ेस (यूआई) की स्थितियों के लिए, इस बात का ध्यान रखना खास तौर पर ज़रूरी है. अगर उपयोगकर्ता 'रोकें' बटन दबाता है, तो 'रोकें' बटन को बंद करें और स्वास्थ्य सेवाओं के लिए pauseExerciseAsync() को चालू करें. ExerciseUpdate.exerciseStateInfo.state का इस्तेमाल करके, Health Services को रोके गए मोड में आने दें. इसके बाद, फिर से शुरू करने के लिए बटन को चालू करें. ऐसा इसलिए होता है, क्योंकि बटन दबाने की तुलना में, Health Services की स्थिति के अपडेट को डिलीवर होने में ज़्यादा समय लग सकता है. इसलिए, अगर यूज़र इंटरफ़ेस (यूआई) में होने वाले सभी बदलावों को बटन दबाने से जोड़ दिया जाता है, तो यूज़र इंटरफ़ेस (यूआई), Health Services की स्थिति के साथ सिंक नहीं हो पाएगा.

इन बातों का ध्यान रखें:

  • अपने-आप रुकने की सुविधा चालू है: कसरत, उपयोगकर्ता के इंटरैक्शन के बिना रुक सकती है या शुरू हो सकती है.
  • किसी दूसरे ऐप्लिकेशन से कसरत शुरू होने पर: ऐसा हो सकता है कि आपकी कसरत, उपयोगकर्ता के इंटरैक्शन के बिना बंद हो जाए.

अगर आपके ऐप्लिकेशन के वर्कआउट को किसी दूसरे ऐप्लिकेशन से बंद कर दिया जाता है, तो आपके ऐप्लिकेशन को इस स्थिति को सही तरीके से हैंडल करना होगा:

  • वर्कआउट की अधूरी स्थिति को सेव करें, ताकि उपयोगकर्ता की प्रोग्रेस मिट न जाए.
  • 'जारी गतिविधि' आइकॉन हटाएं और उपयोगकर्ता को एक सूचना भेजें. इसमें उसे बताएं कि उसके वर्कआउट को किसी दूसरे ऐप्लिकेशन ने बंद कर दिया है.

साथ ही, इस मामले को भी हैंडल करें कि कसरत के दौरान अनुमतियां रद्द कर दी गई हैं. इसे isEnded स्टेट का इस्तेमाल करके भेजा जाता है. इसमें AUTO_END_PERMISSION_LOST का ExerciseEndReason होता है. इस मामले को, बंद करने के मामले की तरह ही हैंडल करें: आंशिक स्थिति को सेव करें, 'जारी है' गतिविधि का आइकॉन हटाएं, और उपयोगकर्ता को इस बारे में सूचना भेजें कि क्या हुआ.

यहां दिए गए उदाहरण में, सही तरीके से बंद होने की स्थिति की जांच करने का तरीका बताया गया है:

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

ऐप्लिकेशन इस्तेमाल करने की अवधि मैनेज करना

कसरत के दौरान, कोई ऐप्लिकेशन वर्कआउट की अवधि दिखा सकता है. ऐप्लिकेशन, Health Services, और डिवाइस की माइक्रो कंट्रोलर यूनिट (एमसीयू) को सिंक में होना चाहिए. एमसीयू, कम पावर वाला प्रोसेसर होता है, जो कसरत को ट्रैक करने के लिए ज़िम्मेदार होता है. इन सभी को एक ही समय पर चालू होना चाहिए. इसे मैनेज करने के लिए, Health Services एक ActiveDurationCheckpoint भेजता है. इससे ऐप्लिकेशन को एक ऐंकर पॉइंट मिलता है, जहां से वह अपना टाइमर शुरू कर सकता है.

चालू रहने की अवधि का डेटा, एमसीयू से भेजा जाता है. इसे ऐप्लिकेशन में पहुंचने में थोड़ा समय लग सकता है. इसलिए, ActiveDurationCheckpoint में दो प्रॉपर्टी होती हैं:

  • activeDuration: यह कसरत कितने समय से चालू है
  • time: जब सक्रिय अवधि का हिसाब लगाया गया था

इसलिए, ऐप्लिकेशन में किसी कसरत की ऐक्टिव अवधि का हिसाब ActiveDurationCheckpoint से लगाया जा सकता है. इसके लिए, इस समीकरण का इस्तेमाल करें:

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

इससे, एमसीयू पर गतिविधि के समय की गिनती करने और ऐप्लिकेशन पर पहुंचने के बीच के छोटे डेल्टा का पता चलता है. इसका इस्तेमाल, ऐप्लिकेशन में क्रोनोमीटर को सीड करने के लिए किया जा सकता है. इससे यह पक्का करने में मदद मिलती है कि ऐप्लिकेशन का टाइमर, Health Services और एमसीयू के समय के साथ पूरी तरह से अलाइन हो.

अगर कसरत को रोका जाता है, तो ऐप्लिकेशन यूज़र इंटरफ़ेस (यूआई) में टाइमर को फिर से चालू करने के लिए तब तक इंतज़ार करता है, जब तक कि कैलकुलेट किया गया समय, यूज़र इंटरफ़ेस (यूआई) पर दिखने वाले समय से ज़्यादा न हो जाए. ऐसा इसलिए होता है, क्योंकि 'रोकें' सिग्नल, हेल्थ सेवाओं और एमसीयू तक थोड़ी देर बाद पहुंचता है. उदाहरण के लिए, अगर ऐप्लिकेशन को t=10 सेकंड पर रोका जाता है, तो हो सकता है कि Health Services, ऐप्लिकेशन को PAUSED अपडेट t=10.2 सेकंड तक न दे.

ExerciseClient से मिले डेटा का इस्तेमाल करना

आपका ऐप्लिकेशन जिन डेटा टाइप के लिए रजिस्टर किया गया है उनकी मेट्रिक, ExerciseUpdate मैसेज में डिलीवर की जाती हैं.

प्रोसेसर, मैसेज सिर्फ़ तब डिलीवर करता है, जब वह चालू हो या जब रिपोर्टिंग की ज़्यादा से ज़्यादा अवधि पूरी हो गई हो. जैसे, हर 150 सेकंड में. ExerciseUpdate की मदद से क्रोनोमीटर को आगे बढ़ाने के लिए, ExerciseUpdate की फ़्रीक्वेंसी पर भरोसा न करें.activeDuration इंडिपेंडेंट क्रोनोमीटर को लागू करने का उदाहरण देखने के लिए, GitHub पर एक्सरसाइज़ का सैंपल देखें.

जब कोई उपयोगकर्ता कसरत शुरू करता है, तब ExerciseUpdate मैसेज बार-बार डिलीवर किए जा सकते हैं. जैसे, हर सेकंड में. उपयोगकर्ता के वर्कआउट शुरू करने पर, स्क्रीन बंद हो सकती है. इसके बाद, Health Services कम बार डेटा भेज सकती है. हालांकि, डेटा को उसी फ़्रीक्वेंसी पर सैंपल किया जाएगा, ताकि मुख्य प्रोसेसर को चालू न करना पड़े. जब उपयोगकर्ता स्क्रीन देखता है, तो बैच में शामिल किया जा रहा कोई भी डेटा तुरंत आपके ऐप्लिकेशन को डिलीवर कर दिया जाता है.

बैचिंग की दर को कंट्रोल करना

कुछ स्थितियों में, आपको यह कंट्रोल करना पड़ सकता है कि स्क्रीन बंद होने पर, आपका ऐप्लिकेशन कितनी बार कुछ खास तरह का डेटा पाए. BatchingMode ऑब्जेक्ट की मदद से, आपका ऐप्लिकेशन डेटा को ज़्यादा बार पाने के लिए, बैचिंग के डिफ़ॉल्ट तरीके को बदल सकता है.

इनमें, स्मार्टवॉच से मोबाइल डिवाइस पर लगातार धड़कन की दर को स्ट्रीम करना भी शामिल है.

बैचिंग की दर को कॉन्फ़िगर करने के लिए, यह तरीका अपनाएं:

  1. देखें कि डिवाइस पर BatchingMode की परिभाषा काम करती है या नहीं:

    // 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. यह बताएं कि ExerciseConfig ऑब्जेक्ट को किसी खास BatchingMode का इस्तेमाल करना चाहिए. इसके लिए, यहां दिए गए कोड स्निपेट का इस्तेमाल करें.

    val config = ExerciseConfig(
        exerciseType = ExerciseType.WORKOUT,
        dataTypes = setOf(
            DataType.HEART_RATE_BPM,
            DataType.TOTAL_CALORIES
        ),
        // ...
        batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    )
    
  3. कसरत के दौरान, BatchingMode को डाइनैमिक तरीके से कॉन्फ़िगर किया जा सकता है. हालांकि, ऐसा करना ज़रूरी नहीं है. इससे, कसरत की पूरी अवधि के दौरान बैचिंग के किसी खास तरीके का इस्तेमाल करने के बजाय, अलग-अलग तरीकों का इस्तेमाल किया जा सकता है:

    val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
    
  4. कस्टम किए गए BatchingMode को हटाने और डिफ़ॉल्ट सेटिंग पर वापस जाने के लिए, BatchingMode में एक खाली सेट पास करें.exerciseClient.overrideBatchingModesForActiveExercise()

टाइमस्टैंप

हर डेटा पॉइंट का पॉइंट-इन-टाइम, डिवाइस के बूट होने के बाद से गुज़रा हुआ समय दिखाता है. इसे टाइमस्टैंप में बदलने के लिए, यह तरीका अपनाएं:

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

इसके बाद, इस वैल्यू का इस्तेमाल हर डेटा पॉइंट के लिए getStartInstant() या getEndInstant() के साथ किया जा सकता है.

डेटा का सटीक होना

कुछ डेटा टाइप के लिए, हर डेटा पॉइंट से जुड़ी सटीक जानकारी उपलब्ध हो सकती है. इसे accuracy प्रॉपर्टी में दिखाया जाता है.

HEART_RATE_BPM और LOCATION डेटा टाइप के लिए, HrAccuracy और LocationAccuracy क्लास भरी जा सकती हैं. अगर मौजूद हो, तो accuracy प्रॉपर्टी का इस्तेमाल करके यह तय करें कि हर डेटा पॉइंट, आपके ऐप्लिकेशन के लिए काफ़ी सटीक है या नहीं.

डेटा सेव और अपलोड करना

Health Services से मिले डेटा को सेव करने के लिए, Room का इस्तेमाल करें. डेटा अपलोड करने की प्रोसेस, Work Manager जैसे किसी मेकेनिज़्म का इस्तेमाल करके, आखिर में पूरी की जाती है. इससे यह पुष्टि करने में मदद मिलती है कि डेटा अपलोड करने के लिए नेटवर्क कॉल तब तक नहीं किए जाते, जब तक कि कसरत पूरी न हो जाए. इससे कसरत के दौरान बिजली की खपत कम होती है और काम आसान हो जाता है.

एकीकरण चेकलिस्ट

Health Services के ExerciseClient का इस्तेमाल करने वाले ऐप्लिकेशन को पब्लिश करने से पहले, इस चेकलिस्ट को देखें. इससे आपको यह पुष्टि करने में मदद मिलेगी कि आपके ऐप्लिकेशन में, उपयोगकर्ता अनुभव से जुड़ी कुछ सामान्य समस्याएं नहीं हैं. पुष्टि करें कि:

  • आपका ऐप्लिकेशन, हर बार चालू होने पर, एक्सरसाइज़ के टाइप और डिवाइस की सुविधाओं की जांच करता है. इस तरह, यह पता लगाया जा सकता है कि कोई डिवाइस या कसरत, आपके ऐप्लिकेशन के लिए ज़रूरी डेटा टाइप में से किसी एक के साथ काम नहीं करती है.
  • ज़रूरी अनुमतियों का अनुरोध करें और उन्हें अपनी मेनिफ़ेस्ट फ़ाइल में शामिल करें. prepareExerciseAsync() को कॉल करने से पहले, आपका ऐप्लिकेशन पुष्टि करता है कि रनटाइम की अनुमतियां दी गई हैं.
  • आपका ऐप्लिकेशन, getCurrentExerciseInfoAsync() का इस्तेमाल करके इन मामलों को हैंडल करता है:
    • पहले से ही किसी कसरत को ट्रैक किया जा रहा है और आपका ऐप्लिकेशन पिछली कसरत को बदल देता है.
    • किसी दूसरे ऐप्लिकेशन ने आपकी कसरत बंद कर दी है. ऐसा तब हो सकता है, जब उपयोगकर्ता ऐप्लिकेशन को फिर से खोलता है. उसे एक मैसेज दिखता है, जिसमें बताया जाता है कि किसी दूसरे ऐप्लिकेशन के चालू होने की वजह से, कसरत बंद हो गई है.
  • अगर LOCATION डेटा का इस्तेमाल किया जा रहा है, तो:
    • आपका ऐप्लिकेशन, कसरत के दौरान (तैयारी के लिए कॉल भी शामिल है) foregroundServiceType के साथ ForegroundService बनाए रखता है.
    • यह कुकी, isProviderEnabled(LocationManager.GPS_PROVIDER) का इस्तेमाल करके यह देखती है कि डिवाइस पर जीपीएस चालू है या नहीं. अगर ज़रूरी हो, तो यह उपयोगकर्ता को जगह की सेटिंग खोलने के लिए भी कहती है.
    • ऐसे मामलों में जहां कम समय में जगह की जानकारी का डेटा पाना बहुत ज़रूरी होता है, फ़्यूज़्ड लोकेशन प्रोवाइडर (एफ़एलपी) को इंटिग्रेट करें और उसके डेटा का इस्तेमाल, शुरुआती जगह की जानकारी के तौर पर करें. जब Health Services से जगह की ज़्यादा सटीक जानकारी मिलती है, तो FLP के बजाय उसका इस्तेमाल करें.
  • अगर आपके ऐप्लिकेशन को डेटा अपलोड करने की ज़रूरत है, तो डेटा अपलोड करने के लिए किए गए सभी नेटवर्क कॉल, इस प्रोसेस के खत्म होने तक रोक दिए जाते हैं. इसके अलावा, इस प्रोसेस के दौरान आपका ऐप्लिकेशन, नेटवर्क कॉल की ज़रूरत पड़ने पर ही कॉल करता है.