ट्रेनिंग के प्लान

यह गाइड, Health Connect के वर्शन 1.1.0-alpha11 के साथ काम करती है.

Health Connect, प्लान की गई कसरत डेटा टाइप उपलब्ध कराता है. इससे ट्रेनिंग ऐप्लिकेशन, ट्रेनिंग प्लान बना सकते हैं. साथ ही, कसरत वाले ऐप्लिकेशन, ट्रेनिंग प्लान पढ़ सकते हैं. रिकॉर्ड की गई कसरतों (वर्कआउट) को फिर से पढ़ा जा सकता है, ताकि लोगों को उनकी परफ़ॉर्मेंस का विश्लेषण करके बताया जा सके. इससे लोगों को ट्रेनिंग के लक्ष्यों को हासिल करने में मदद मिलती है.

सुविधा की उपलब्धता

यह पता लगाने के लिए कि उपयोगकर्ता के डिवाइस पर Health Connect के ट्रेनिंग प्लान काम करते हैं या नहीं, क्लाइंट पर FEATURE_PLANNED_EXERCISE की उपलब्धता देखें:

if (healthConnectClient
     .features
     .getFeatureStatus(
       HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
     ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {

  // Feature is available
} else {
  // Feature isn't available
}

ज़्यादा जानने के लिए, सुविधा की उपलब्धता की जांच करना लेख पढ़ें.

ज़रूरी अनुमतियां

एक्सरसाइज़ के प्लान का ऐक्सेस, इन अनुमतियों से सुरक्षित होता है:

  • android.permission.health.READ_PLANNED_EXERCISE
  • android.permission.health.WRITE_PLANNED_EXERCISE

अपने ऐप्लिकेशन में प्लान की गई कसरत की सुविधा जोड़ने के लिए, PlannedExerciseSession डेटा टाइप के लिए लिखने की अनुमतियों का अनुरोध करें.

यहाँ दी गई अनुमति का एलान करना ज़रूरी है, ताकि प्लान की गई कसरत की जानकारी लिखी जा सके:

<application>
  <uses-permission
android:name="android.permission.health.WRITE_PLANNED_EXERCISE" />
...
</application>

प्लान की गई कसरत की जानकारी पढ़ने के लिए, आपको ये अनुमतियां मांगनी होंगी:

<application>
  <uses-permission
android:name="android.permission.health.READ_PLANNED_EXERCISE" />
...
</application>

उपयोगकर्ता से अनुमतियों का अनुरोध करना

क्लाइंट इंस्टेंस बनाने के बाद, आपके ऐप्लिकेशन को उपयोगकर्ता से अनुमतियों का अनुरोध करना होगा. उपयोगकर्ताओं को किसी भी समय अनुमतियां देने या अस्वीकार करने की अनुमति होनी चाहिए.

इसके लिए, ज़रूरी डेटा टाइप के लिए अनुमतियों का सेट बनाएं. पक्का करें कि सेट में मौजूद अनुमतियों का एलान, सबसे पहले आपके Android मेनिफ़ेस्ट में किया गया हो.

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
  HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class),
  HealthPermission.getReadPermission(ExerciseSessionRecord::class),
  HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)

getGrantedPermissions का इस्तेमाल करके देखें कि आपके ऐप्लिकेशन को ज़रूरी अनुमतियां पहले से मिली हुई हैं या नहीं. अगर ऐसा नहीं है, तो उन अनुमतियों का अनुरोध करने के लिए createRequestPermissionResultContract का इस्तेमाल करें. इससे Health Connect की अनुमतियों वाली स्क्रीन दिखती है.

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

उपयोगकर्ता किसी भी समय अनुमतियां दे सकते हैं या उन्हें रद्द कर सकते हैं. इसलिए, आपके ऐप्लिकेशन को समय-समय पर यह जांच करनी चाहिए कि कौनसी अनुमतियां दी गई हैं. साथ ही, उन स्थितियों को मैनेज करना चाहिए जिनमें अनुमति नहीं दी गई है.

ट्रेनिंग प्लान, एक्सरसाइज़ सेशन से लिंक होते हैं. इसलिए, उपयोगकर्ता को ट्रेनिंग प्लान से जुड़े हर रिकॉर्ड टाइप का इस्तेमाल करने की अनुमति देनी होगी, ताकि Health Connect की इस सुविधा का पूरा फ़ायदा उठाया जा सके.

उदाहरण के लिए, अगर ट्रेनिंग प्लान में कई बार दौड़ने के दौरान किसी व्यक्ति की दिल की धड़कन को मापा जाता है, तो डेवलपर को ये अनुमतियां देनी पड़ सकती हैं. साथ ही, उपयोगकर्ता को ये अनुमतियां देनी पड़ सकती हैं, ताकि कसरत के सेशन को लिखा जा सके और बाद में आकलन करने के लिए नतीजे पढ़े जा सकें:

  • android.permission.health.READ_EXERCISE
  • android.permission.health.READ_EXERCISE_ROUTES
  • android.permission.health.READ_HEART_RATE
  • android.permission.health.WRITE_EXERCISE
  • android.permission.health.WRITE_EXERCISE_ROUTE
  • android.permission.health.WRITE_HEART_RATE

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

ट्रेनिंग प्लान ऐप्लिकेशन वर्कआउट ऐप्लिकेशन
WRITE_PLANNED_EXERCISE READ_PLANNED_EXERCISE
READ_EXERCISE WRITE_EXERCISE
READ_EXERCISE_ROUTES WRITE_EXERCISE_ROUTE
READ_HEART_RATE WRITE_HEART_RATE

कसरत के प्लान किए गए सेशन के रिकॉर्ड में शामिल जानकारी

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

प्लान की गई कसरत के ब्लॉक के रिकॉर्ड में शामिल जानकारी

प्लान किए गए वर्कआउट ब्लॉक में, वर्कआउट के चरणों की सूची होती है. इससे चरणों के अलग-अलग ग्रुप को दोहराने में मदद मिलती है. उदाहरण के लिए, आर्म कर्ल, बर्पी, और क्रंच को पांच बार दोहराएं.

कसरत के प्लान किए गए किसी चरण के रिकॉर्ड में शामिल जानकारी

इस्तेमाल किए जा सकने वाले एग्रीगेशन

इस डेटा टाइप के लिए, एग्रीगेशन की सुविधा काम नहीं करती.

इस्तेमाल का उदाहरण

मान लें कि किसी उपयोगकर्ता को दो दिन बाद 90 मिनट तक दौड़ लगानी है. इस रन में, झील के चारों ओर तीन लैप होंगे. साथ ही, धड़कन की दर 90 से 110 बीपीएम के बीच होनी चाहिए.

  1. उपयोगकर्ता ने ट्रेनिंग प्लान वाले ऐप्लिकेशन में, कसरत के लिए एक प्लान बनाया है. इसमें ये चीज़ें शामिल हैं:
    1. रन के शुरू और खत्म होने का प्लान किया गया समय
    2. कसरत का टाइप (दौड़ना)
    3. लैप की संख्या (दोहराव)
    4. धड़कन की दर के लिए परफ़ॉर्मेंस टारगेट (90 से 110 बीपीएम के बीच)
  2. इस जानकारी को कसरत के ब्लॉक और चरणों में ग्रुप किया जाता है. साथ ही, ट्रेनिंग प्लान ऐप्लिकेशन इसे Health Connect में PlannedExerciseSessionRecord के तौर पर सेव करता है.
  3. उपयोगकर्ता प्लान किया गया सेशन (चालू है) पूरा करता है.
  4. सेशन से जुड़ा कसरत का डेटा इनमें से किसी एक तरीके से रिकॉर्ड किया जाता है:
    1. सेशन के दौरान, पहने जाने वाले डिवाइस से. उदाहरण के लिए, धड़कन की दर. इस डेटा को Health Connect में, गतिविधि के रिकॉर्ड टाइप के तौर पर सेव किया जाता है. इस मामले में, HeartRateRecord.
    2. उपयोगकर्ता, सेशन के बाद इसे मैन्युअल तरीके से सेट करता है. उदाहरण के लिए, दौड़ शुरू और खत्म होने का समय बताना. इस डेटा को Health Connect में ExerciseSessionRecord के तौर पर सेव किया जाता है.
  5. बाद में, ट्रेनिंग प्लान ऐप्लिकेशन, Health Connect से डेटा पढ़ता है. इससे यह पता चलता है कि उपयोगकर्ता ने प्लान किए गए कसरत सेशन में जो टारगेट सेट किए थे उनके हिसाब से उसकी परफ़ॉर्मेंस कैसी रही.

एक्सरसाइज़ प्लान करना और टारगेट सेट करना

कोई उपयोगकर्ता आने वाले समय में की जाने वाली कसरत का प्लान बना सकता है और उसके लिए टारगेट सेट कर सकता है. इसे Health Connect में कसरत के प्लान किए गए सेशन के तौर पर लिखो.

इस्तेमाल का उदाहरण में बताए गए उदाहरण में, उपयोगकर्ता को दो दिन बाद 90 मिनट तक दौड़ लगानी है. इस रन में, झील के चारों ओर तीन लैप शामिल होंगे. इसमें धड़कन की दर 90 से 110 बीपीएम के बीच होनी चाहिए.

इस तरह का स्निपेट, किसी ऐसे ऐप्लिकेशन के फ़ॉर्म हैंडलर में मिल सकता है जो प्लान किए गए कसरत सेशन को Health Connect में लॉग करता है. इसे इंटिग्रेशन के लिए डेटा सोर्स में भी देखा जा सकता है. जैसे, ट्रेनिंग देने वाली किसी सेवा के साथ इंटिग्रेशन के लिए डेटा सोर्स.

// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(PlannedExerciseSessionRecord::class))) {
    // The user hasn't granted the app permission to write planned exercise session data.
    return
}

val plannedDuration = Duration.ofMinutes(90)
val plannedStartDate = LocalDate.now().plusDays(2)

val plannedExerciseSessionRecord = PlannedExerciseSessionRecord(
    startDate = plannedStartDate,
    duration = plannedDuration,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    blocks = listOf(
        PlannedExerciseBlock(
            repetitions = 1, steps = listOf(
                PlannedExerciseStep(
                    exerciseType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING,
                    exercisePhase = PlannedExerciseStep.EXERCISE_PHASE_ACTIVE,
                    completionGoal = ExerciseCompletionGoal.RepetitionsGoal(repetitions = 3),
                    performanceTargets = listOf(
                        ExercisePerformanceTarget.HeartRateTarget(
                            minHeartRate = 90.0, maxHeartRate = 110.0
                        )
                    )
                ),
            ), description = "Three laps around the lake"
        )
    ),
    title = "Run at lake",
    notes = null,
    metadata = Metadata.manualEntry(
      device = Device(type = Device.Companion.TYPE_PHONE)
    )
)
val insertedPlannedExerciseSessions =
    healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)).recordIdsList
val insertedPlannedExerciseSessionId = insertedPlannedExerciseSessions.first()

कसरत और गतिविधि का डेटा लॉग करना

दो दिन बाद, उपयोगकर्ता ने कसरत का असली सेशन लॉग किया. इसे Health Connect में कसरत के सेशन के तौर पर सेव करो.

इस उदाहरण में, उपयोगकर्ता के सेशन की अवधि, प्लान की गई अवधि से पूरी तरह मेल खाती है.

यहां दिया गया स्निपेट, किसी ऐसे ऐप्लिकेशन के फ़ॉर्म हैंडलर में मिल सकता है जो कसरत के सेशन को Health Connect में लॉग करता है. यह डेटा, पहनने लायक ऐसे डिवाइस के डेटा को इकट्ठा करने और एक्सपोर्ट करने वाले हैंडलर में भी मिल सकता है जो कसरत के सेशन का पता लगा सकता है और उन्हें लॉग कर सकता है.

यहां insertedPlannedExerciseSessionId का इस्तेमाल पिछले उदाहरण से किया गया है. असली ऐप्लिकेशन में, आईडी का पता तब चलेगा, जब उपयोगकर्ता मौजूदा सेशन की सूची से प्लान की गई कसरत का सेशन चुनेगा.

// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(ExerciseSessionRecord::class))) {
    // The user doesn't granted the app permission to write exercise session data.
    return
}

val sessionDuration = Duration.ofMinutes(90)
val sessionEndTime = Instant.now()
val sessionStartTime = sessionEndTime.minus(sessionDuration)

val exerciseSessionRecord = ExerciseSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
    segments = listOf(
        ExerciseSegment(
            startTime = sessionStartTime,
            endTime = sessionEndTime,
            repetitions = 3,
            segmentType = ExerciseSegment.EXERCISE_SEGMENT_TYPE_RUNNING
        )
    ),
    title = "Run at lake",
    plannedExerciseSessionId = insertedPlannedExerciseSessionId,
    metadata = Metadata.manualEntry(
      device = Device(type = Device.Companion.TYPE_PHONE)
    )
)
val insertedExerciseSessions =
    healthConnectClient.insertRecords(listOf(exerciseSessionRecord))

साथ ही, पहनने लायक डिवाइस से दौड़ के दौरान धड़कन की दर का डेटा भी लॉग किया जाता है. नीचे दिए गए स्निपेट का इस्तेमाल, टारगेट रेंज में रिकॉर्ड जनरेट करने के लिए किया जा सकता है.

किसी असली ऐप्लिकेशन में, इस स्निपेट के मुख्य हिस्से, पहनने लायक डिवाइस से मिले मैसेज के हैंडलर में मिल सकते हैं. यह हैंडलर, डेटा इकट्ठा होने पर Health Connect में मेज़रमेंट लिखता है.

// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
    healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
      HealthPermission.getWritePermission(HeartRateRecord::class))) {
    // The user doesn't granted the app permission to write heart rate record data.
    return
}

val samples = mutableListOf<HeartRateRecord.Sample>()
var currentTime = sessionStartTime
while (currentTime.isBefore(sessionEndTime)) {
    val bpm = Random.nextInt(21) + 90
    val heartRateRecord = HeartRateRecord.Sample(
        time = currentTime,
        beatsPerMinute = bpm.toLong(),
    )
    samples.add(heartRateRecord)
    currentTime = currentTime.plusSeconds(180)
}

val heartRateRecord = HeartRateRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    samples = samples,
    metadata = Metadata.autoRecorded(
      device = Device(type = Device.Companion.TYPE_WATCH)
    )
)
val insertedHeartRateRecords = healthConnectClient.insertRecords(listOf(heartRateRecord))

परफ़ॉर्मेंस टारगेट का आकलन करना

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

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

// Verify the user has granted all necessary permissions for this task
val grantedPermissions =
     healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.containsAll(
        listOf(
            HealthPermission.getReadPermission(ExerciseSessionRecord::class),
            HealthPermission.getReadPermission(PlannedExerciseSessionRecord::class),
            HealthPermission.getReadPermission(HeartRateRecord::class)
        )
    )
) {
    // The user doesn't granted the app permission to read exercise session record data.
    return
}

val searchDuration = Duration.ofDays(1)
val searchEndTime = Instant.now()
val searchStartTime = searchEndTime.minus(searchDuration)

val response = healthConnectClient.readRecords(
    ReadRecordsRequest<ExerciseSessionRecord>(
        timeRangeFilter = TimeRangeFilter.between(searchStartTime, searchEndTime)
    )
)
for (exerciseRecord in response.records) {
    val plannedExerciseRecordId = exerciseRecord.plannedExerciseSessionId
    val plannedExerciseRecord =
        if (plannedExerciseRecordId == null) null else healthConnectClient.readRecord(
            PlannedExerciseSessionRecord::class, plannedExerciseRecordId
        ).record
    if (plannedExerciseRecord != null) {
        val aggregateRequest = AggregateRequest(
            metrics = setOf(HeartRateRecord.BPM_AVG),
            timeRangeFilter = TimeRangeFilter.between(
                exerciseRecord.startTime, exerciseRecord.endTime
            ),
        )
        val aggregationResult = healthConnectClient.aggregate(aggregateRequest)

        val maxBpm = aggregationResult[HeartRateRecord.BPM_MAX]
        val minBpm = aggregationResult[HeartRateRecord.BPM_MIN]
        if (maxBpm != null && minBpm != null) {
            plannedExerciseRecord.blocks.forEach { block ->
                block.steps.forEach { step ->
                    step.performanceTargets.forEach { target ->
                        when (target) {
                            is ExercisePerformanceTarget.HeartRateTarget -> {
                                val minTarget = target.minHeartRate
                                val maxTarget = target.maxHeartRate
                                if(
                                    minBpm >= minTarget && maxBpm <= maxTarget
                                ) {
                                  // Success!
                                }
                            }
                            // Handle more target types
                            }
                        }
                    }
                }
            }
        }
    }
}

कसरत के सेशन

एक्सरसाइज़ सेशन में, दौड़ने से लेकर बैडमिंटन खेलने तक कुछ भी शामिल हो सकता है.

कसरत के सेशन का डेटा सेव करने की अनुमति दें

सेशन शामिल करने का अनुरोध इस तरह बनाया जाता है:

suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
    healthConnectClient.insertRecords(
        listOf(
            ExerciseSessionRecord(
                startTime = START_TIME,
                startZoneOffset = START_ZONE_OFFSET,
                endTime = END_TIME,
                endZoneOffset = END_ZONE_OFFSET,
                exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
                title = "My Run"
            ),
            // ... other records
        )
    )
}

कसरत के सेशन का डेटा पढ़ने की अनुमति दें

यहां कसरत के सेशन को पढ़ने का तरीका बताया गया है:

suspend fun readExerciseSessions(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.readRecords(
            ReadRecordsRequest(
                ExerciseSessionRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    for (exerciseRecord in response.records) {
        // Process each exercise record
        // Optionally pull in with other data sources of the same time range.
        val distanceRecord =
            healthConnectClient
                .readRecords(
                    ReadRecordsRequest(
                        DistanceRecord::class,
                        timeRangeFilter =
                            TimeRangeFilter.between(
                                exerciseRecord.startTime,
                                exerciseRecord.endTime
                            )
                    )
                )
                .records
    }
}

सबटाइप का डेटा सेव करने की अनुमति दें

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

उदाहरण के लिए, कसरत वाले सेशन में ExerciseSegment, ExerciseLap, और ExerciseRoute क्लास शामिल की जा सकती हैं:

val segments = listOf(
  ExerciseSegment(
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
    segmentType = ActivitySegmentType.BENCH_PRESS,
    repetitions = 373
  )
)

val laps = listOf(
  ExerciseLap(
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
    length = 0.meters
  )
)

ExerciseSessionRecord(
  exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
    startTime = Instant.parse("2022-01-02T10:10:10Z"),
    endTime = Instant.parse("2022-01-02T10:10:13Z"),
  startZoneOffset = ZoneOffset.UTC,
  endZoneOffset = ZoneOffset.UTC,
  segments = segments,
  laps = laps,
  route = route
)