Health Connect نوع داده تمرین برنامهریزیشده را ارائه میدهد تا برنامههای تمرینی بتوانند برنامههای تمرینی بنویسند و برنامههای تمرین بتوانند برنامههای تمرینی را بخوانند. تمرینهای ضبطشده (تمرینها) را میتوان برای تجزیهوتحلیل عملکرد شخصیسازیشده بازخوانی کرد تا به کاربران کمک شود به اهداف تمرینی خود دست یابند.
بررسی دردسترس بودن Health Connect
برنامه شما باید قبلاز تلاش برای استفاده از Health Connect، بررسی کند که آیا Health Connect در دستگاه کاربر دردسترس است یا نه. Health Connect ممکن است در همه دستگاهها پیشنصب نشده باشد یا ممکن است غیرفعال باشد.
بااستفاده از روش HealthConnectClient.getSdkStatus() میتوانید دردسترس بودن را بررسی کنید.
نحوه بررسی دردسترس بودن Health Connect
fun checkHealthConnectAvailability(context: Context) { val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName) if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) { // Health Connect is not available. Guide the user to install/enable it. // For example, show a dialog. return // early return as there is no viable integration } if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) { // Health Connect is available but requires an update. // Optionally redirect to package installer to find a provider, for example: val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding" context.startActivity( Intent(Intent.ACTION_VIEW).apply { setPackage("com.android.vending") data = Uri.parse(uriString) putExtra("overlay", true) putExtra("callerId", context.packageName) } ) return } // Health Connect is available, obtain a HealthConnectClient instance val healthConnectClient = HealthConnectClient.getOrCreate(context) // Issue operations with healthConnectClient }
بسته به وضعیتی که getSdkStatus() برمیگرداند، میتوانید کاربر را راهنمایی کنید
تا درصورت لزوم «اتصال به خدمات بهداشتی» را از «فروشگاه Google Play» نصب یا بهروزرسانی کند.
دردسترس بودن ویژگی
برای تعیین اینکه آیا دستگاه کاربر از طرحهای تمرینی در «اتصال به Health» پشتیبانی میکند یا نه، دردسترس بودن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_EXERCISEandroid.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 شما اعلام شده باشد.
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 نمایش داده میشود.
val permissions = setOf( HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class), HealthPermission.getReadPermission(HeartRateRecord::class), HealthPermission.getWritePermission(HeartRateRecord::class) ) val requestPermissionsLauncher = rememberLauncherForActivityResult( contract = PermissionController.createRequestPermissionResultContract() ) { grantedPermissions -> if (grantedPermissions.containsAll(permissions)) { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") } } else { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") } } }
اجازههای مرتبط
طرحهای تمرین به جلسات تمرین پیوند داده میشوند. بنابراین، کاربر باید برای استفاده از هر نوع سابقه مربوط به طرح تمرینی اجازه بدهد تا بتواند بهطور کامل از این ویژگی Health Connect استفاده کند.
برای مثال، اگر طرح تمرینی ضربان قلب کاربر را درطول مجموعهای از دویدنها اندازهگیری کند، توسعهدهنده باید اجازههای زیر را اعلام کند و کاربر باید آنها را اعطا کند تا بتوان جلسه تمرین را نوشت و نتایج را برای ارزیابی بعدی خواند:
android.permission.health.READ_EXERCISEandroid.permission.health.READ_EXERCISE_ROUTESandroid.permission.health.READ_HEART_RATEandroid.permission.health.WRITE_EXERCISEandroid.permission.health.WRITE_EXERCISE_ROUTEandroid.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 |
اطلاعات موجود در سابقه جلسه تمرین برنامهریزیشده
- عنوان جلسه.
- فهرست بلوکهای تمرین برنامهریزیشده.
- زمان شروع و پایان جلسه.
- نوع تمرین.
- یادداشتهای فعالیت.
- فراداده.
- شناسه جلسه تمرین تکمیلشده — این شناسه بهطور خودکار پساز تکمیل جلسه تمرین مربوط به این جلسه تمرین برنامهریزیشده نوشته میشود.
اطلاعات موجود در سابقه واحد تمرین برنامهریزیشده
بلوک تمرین برنامهریزیشده حاوی فهرستی از مراحل تمرین است تا از تکرار گروههای مختلف مراحل پشتیبانی کند (برای مثال، انجام توالی پنجتایی از تمرینهای خم کردن بازو، بارپی، و کرانچ).
- شرح بلوک.
- فهرستی از مراحل تمرین برنامهریزیشده.
- تعداد تکرارها.
اطلاعات موجود در سابقه گام تمرین برنامهریزیشده
- شرح مرحله.
- دسته تمرین.
- نوع تمرین.
- فهرستی از هدفهای عملکرد.
- هدف تکمیل.
تجمعهای پشتیبانیشده
برای این نوع داده، تجمیع پشتیبانیشدهای وجود ندارد.
نمونه استفاده
فرض کنید کاربری برای دو روز بعد یک دویدن ۹۰ دقیقهای برنامهریزی میکند. این تمرین شامل سه دور در اطراف دریاچه با ضربان قلب هدف بین ۹۰ تا ۱۱۰ ضربه در دقیقه است.
- جلسه تمرین برنامهریزیشده با موارد زیر توسط کاربر در
برنامه طرح تمرین تعریف میشود:
- شروع و پایان برنامهریزیشده اجرا
- نوع تمرین (دویدن)
- تعداد دورها (تکرارها)
- هدف عملکرد برای ضربان قلب (بین ۹۰ تا ۱۱۰ ضربه در دقیقه)
- این اطلاعات در بلوکهای تمرین و قدمها گروهبندی میشود و برنامه طرح تمرین آن را بهعنوان
PlannedExerciseSessionRecordدر Health Connect مینویسد. - کاربر جلسه برنامهریزیشده را انجام میدهد (در حال اجرا).
- دادههای تمرین مربوط به جلسه به یکی از روشهای زیر ضبط میشود:
- توسط دستگاه پوشیدنی درطول جلسه. برای مثال، ضربان قلب.
این دادهها بهعنوان نوع سابقه برای فعالیت در Health Connect نوشته میشود. در این مورد،
HeartRateRecord. - بهصورت دستی توسط کاربر پساز جلسه. برای مثال، نشان دادن
شروع و پایان اجرای واقعی. این دادهها بهعنوان
ExerciseSessionRecordدر Health Connect نوشته میشود.
- توسط دستگاه پوشیدنی درطول جلسه. برای مثال، ضربان قلب.
این دادهها بهعنوان نوع سابقه برای فعالیت در Health Connect نوشته میشود. در این مورد،
- در زمانی دیگر، برنامه طرح تمرین دادهها را از Health Connect میخواند تا عملکرد واقعی را درمقایسه با اهداف تعیینشده توسط کاربر در جلسه تمرین برنامهریزیشده ارزیابی کند.
تمرینها را برنامهریزی کنید و هدف تعیین کنید
کاربر میتواند تمرین خود را در آینده برنامهریزی کند و هدف تعیین کند. این را بهعنوان جلسه تمرین برنامهریزیشده در Health Connect بنویس.
در مثال شرحدادهشده در مثال استفاده، کاربر دو روز دیگر قصد دارد ۹۰ دقیقه بدود. این دویدن شامل سه دور اطراف دریاچه با ضربان قلب هدف بین ۹۰ تا ۱۱۰ ضربه در دقیقه است.
تکهکدی مانند این ممکن است در مدیریتکننده فرم برنامهای که جلسات تمرین برنامهریزیشده را در 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. Log.w("HealthConnect", "Write permission for PlannedExerciseSessionRecord not granted.") return } val plannedExerciseSessionRecord = PlannedExerciseSessionRecord( startTime = startTime, endTime = endTime, 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.activelyRecorded( device = Device(type = Device.Companion.TYPE_PHONE), ), startZoneOffset = null, endZoneOffset = null, ) try { // Attempt to insert the record val response = healthConnectClient.insertRecords(listOf(plannedExerciseSessionRecord)) // If execution reaches here, the insert succeeded. // Safely extract the ID using firstOrNull() val insertedPlannedExerciseSessionId = response.recordIdsList.firstOrNull() if (insertedPlannedExerciseSessionId != null) { Log.d("HealthConnect", "Successfully inserted planned exercise session ID: $insertedPlannedExerciseSessionId") } else { Log.w("HealthConnect", "Insertion succeeded but no record IDs were returned.") } } catch (e: Exception) { // Handle API failures, database errors, or system issues safely without crashing Log.e("HealthConnect", "Failed to insert planned exercise session record", e) }
ثبت دادههای فعالیت و تمرین
دو روز بعد، کاربر جلسه تمرین واقعی را ثبت میکند. این را بهعنوان جلسه تمرین در 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.activelyRecorded( 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.activelyRecorded( 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",
metadata = Metadata.manualEntry()
),
// ... 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,
metadata = Metadata.manualEntry()
)