تقدّم "خدمات الصحة" دعمًا من المستوى الأول لتطبيقات التمارين الرياضية من خلال
ExerciseClient
.
باستخدام ExerciseClient
، يمكن لتطبيقك التحكّم في وقت تنفيذ التمارين، وإضافة أهداف التمارين، والحصول على آخر المعلومات عن حالة التمارين أو أحداث التمارين أو مقاييس أخرى مطلوبة. لمزيد من المعلومات، يمكنك الاطّلاع على القائمة الكاملة
لأنواع التمارين الرياضية
التي تتوافق مع "الخدمات الصحية".
اطّلِع على نموذج التمرين على GitHub.
إضافة التبعيات
لإضافة تبعية على "خدمات الصحة"، يجب إضافة مستودع Google Maven إلى مشروعك. لمزيد من المعلومات، اطّلِع على مستودع Maven من Google.
بعد ذلك، أضِف التبعية التالية في ملف 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") }
بنية التطبيق
استخدِم بنية التطبيق التالية عند إنشاء تطبيق تمارين باستخدام الخدمات الصحية:
- يجب أن تكون الشاشات وعناصر التنقّل ضمن نشاط رئيسي.
- إدارة حالة التمارين وبيانات أجهزة الاستشعار والنشاط الجاري والبيانات باستخدام خدمة تعمل في المقدّمة
- تخزين البيانات باستخدام Room، واستخدام WorkManager لتحميل البيانات
عند الاستعداد لإجراء تمرين وأثناء التمرين، قد يتم
إيقاف نشاطك لأسباب مختلفة. قد ينتقل المستخدم إلى تطبيق آخر
أو يعود إلى خلفية شاشة الساعة. قد يعرض النظام رسالة أعلى
نشاطك، أو قد يتم إيقاف الشاشة بعد فترة من عدم النشاط.
استخدِم ForegroundService
مستمرًا مع ExerciseClient
للمساعدة في ضمان التشغيل الصحيح لجلسة التمارين بالكامل.
يتيح لك استخدام 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)
إدارة مدة التمرين
تتيح "خدمات الصحة" ممارسة تمرين واحد كحد أقصى في المرة الواحدة على جميع التطبيقات على الجهاز. إذا كان يتم تتبُّع تمرين وبدأ تطبيق مختلف في تتبُّع تمرين جديد، يتم إنهاء التمرين الأول.
قبل بدء التمرين، عليك اتّباع الخطوات التالية:
- تحقّق مما إذا كان يتم تتبُّع تمرين معيّن، وتصرَّف وفقًا لذلك. على سبيل المثال، اطلب من المستخدم التأكيد قبل إلغاء تمرين سابق والبدء في تتبُّع تمرين جديد.
يوضّح المثال التالي كيفية البحث عن تمرين حالي باستخدام
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
. - تأكَّد من أنّ المستخدم قد منح الأذونات اللازمة. لمزيد من المعلومات، يُرجى الاطّلاع على طلب أذونات التطبيق. ترفض "الخدمات الصحية" الطلب إذا لم يتم منح الأذونات اللازمة مسبقًا.
بالنسبة إلى بيانات الموقع الجغرافي، عليك اتّباع الخطوات الإضافية التالية:
- تأكَّد من تفعيل نظام تحديد المواقع العالمي (GPS) على الجهاز باستخدام
isProviderEnabled(LocationManager.GPS_PROVIDER)
. اطلب من المستخدم فتح إعدادات الموقع الجغرافي إذا لزم الأمر. - تأكَّد من الحفاظ على
ForegroundService
معforegroundServiceType
المناسب طوال التمرين.
الاستعداد لإجراء تمرين رياضي
قد تستغرق بعض أدوات الاستشعار، مثل نظام تحديد المواقع العالمي (GPS) أو معدل ضربات القلب، بعض الوقت للتأهّل، أو قد يريد المستخدم معرفة بياناته قبل بدء التمرين. تتيح الطريقة الاختيارية
prepareExerciseAsync()
لأجهزة الاستشعار هذه الاستعداد لتلقّي البيانات بدون بدء
الموقّت للتمرين. لا يتأثّر activeDuration
بهذه المدّة
التحضيرية.
قبل إجراء المكالمة إلى prepareExerciseAsync()
، يُرجى التحقّق مما يلي:
تحقّق من إعدادات الموقع الجغرافي على مستوى المنصة. يتحكّم المستخدم في هذا الإعداد من قائمة "الإعدادات" الرئيسية، وهو مختلف عن عملية التحقّق من الأذونات على مستوى التطبيق.
إذا كان الإعداد غير مفعَّل، أطلِع المستخدم على أنّه رفض الوصول إلى الموقع الجغرافي، واطلب منه تفعيله إذا كان تطبيقك يتطلّب الوصول إلى الموقع الجغرافي.
تأكَّد من أنّ تطبيقك يتضمّن أذونات التشغيل لأجهزة استشعار الجسم (المستوى 35 أو أقل لواجهة برمجة التطبيقات) أو معدل ضربات القلب (المستوى 36 أو إصدار أحدث لواجهة برمجة التطبيقات) والتعرّف على النشاط والموقع الجغرافي الدقيق. بالنسبة إلى الأذونات غير المتوفّرة، اطلب من المستخدم منح أذونات التشغيل، مع تقديم سياق مناسب. إذا لم يمنح المستخدم إذنًا معيّنًا، عليك إزالة أنواع البيانات المرتبطة بهذا الإذن من طلب
prepareExerciseAsync()
. إذا لم يتم منح إذن استخدام أدوات قياس الوظائف الحيوية (معدّل نبضات القلب على مستوى واجهة برمجة التطبيقات 36 أو أعلى) أو إذن استخدام بيانات الموقع الجغرافي، يجب عدم استدعاءprepareExerciseAsync()
، لأنّ استدعاء الإعداد مخصّص تحديدًا للحصول على معدّل نبضات قلب ثابت أو تحديد الموقع الجغرافي باستخدام نظام تحديد المواقع العالمي (GPS) قبل بدء تمرين. وسيظل بإمكان التطبيق الحصول على المسافة والوتيرة والسرعة والمقاييس الأخرى المستندة إلى الخطوات والتي لا تتطلّب هذه الأذونات.
اتّبِع الخطوات التالية لضمان نجاح مكالمتك إلى 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
، يتم إرسال تعديلات مدى توفّر أجهزة الاستشعار
في الفترة من ExerciseUpdateCallback
إلى onAvailabilityChanged()
.
ويمكن بعد ذلك عرض هذه المعلومات على المستخدم ليقرر ما إذا كان يريد
بدء تمرينه.
بدء التمرين
عندما تريد بدء تمرين، أنشئ 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()
}
يمكنك أيضًا وضع علامة على لفات جميع التمارين. تقدّم "الخدمات الصحية" ملفًا شخصيًا بعنوان
ExerciseLapSummary
يتضمّن مقاييس مجمّعة على مدار مدة اللفة.
يوضّح المثال السابق استخدام isGpsEnabled
، والذي يجب أن يكون صحيحًا عند طلب بيانات الموقع الجغرافي. ومع ذلك، يمكن أن يساعد استخدام نظام تحديد المواقع العالمي (GPS) أيضًا في المقاييس الأخرى.
إذا حدّد ExerciseConfig
المسافة على أنّها DataType
، يتم تلقائيًا
استخدام الخطوات لتقدير المسافة. من خلال تفعيل نظام تحديد المواقع العالمي (GPS) اختياريًا، يمكن استخدام معلومات
الموقع الجغرافي بدلاً من ذلك لتقدير المسافة.
إيقاف تمرين مؤقتًا واستئنافه وإنهائه
يمكنك إيقاف التمارين مؤقتًا واستئنافها وإنهائها باستخدام الطريقة المناسبة، مثل
pauseExerciseAsync()
أو
endExerciseAsync()
.
استخدِم الحالة من ExerciseUpdate
كمصدر المعلومات. لا يتم
اعتبار التمارين الرياضية متوقّفة مؤقتًا عند عودة طلب pauseExerciseAsync()
، ولكن بدلاً من ذلك
عند ظهور هذه الحالة في رسالة ExerciseUpdate
. من المهم بشكل خاص مراعاة ذلك عند التعامل مع حالات واجهة المستخدم. إذا ضغط المستخدم على زر الإيقاف المؤقت،
أوقِف زر الإيقاف المؤقت واتصل برقم pauseExerciseAsync()
في
الخدمات الصحية. انتظِر وصول "خدمات الصحة" إلى حالة التوقف المؤقت
باستخدام ExerciseUpdate.exerciseStateInfo.state
، ثم بدِّل الزر
إلى استئناف. ويعود السبب في ذلك إلى أنّ تعديلات حالة "خدمات الصحة" قد تستغرق وقتًا أطول في
إرسالها مقارنةً بالضغط على الزر، لذا إذا ربطت جميع تغييرات واجهة المستخدم بالضغط على buttons
، يمكن أن تصبح واجهة المستخدم غير متزامنة مع حالة "خدمات الصحة".
يُرجى مراعاة ذلك في الحالات التالية:
- ميزة "الإيقاف المؤقت التلقائي" مفعّلة: يمكن إيقاف التمرين مؤقتًا أو بدؤه بدون تدخل من المستخدم.
- بدء تطبيق آخر لتمرين: قد يتم إنهاء تمرينك بدون تفاعل المستخدم.
إذا أنهى تطبيق آخر جلسة تدريب تطبيقك، يجب أن يتعامل تطبيقك مع عملية الإنهاء بشكلٍ جيد:
- حفظ حالة التمارين الرياضية الجزئية حتى لا يتم محو مستوى تقدّم المستخدم
- أزِل رمز "النشاط الجاري" وأرسِل إشعارًا للمستخدم يُعلمه بأنّ تطبيقًا آخر قد أنهى تمرينه.
عليك أيضًا معالجة الحالة التي يتم فيها إبطال الأذونات أثناء
تمرين جاري. يتم إرسال هذا الطلب باستخدام الحالة isEnded
، مع قيمة
ExerciseEndReason
AUTO_END_PERMISSION_LOST
. يمكنك معالجة هذه الحالة بالطريقة نفسها المتّبعة في حالة
الإيقاف: حفظ الحالة الجزئية، وإزالة رمز
النشاط الجاري، وإرسال إشعار بشأن ما حدث للمستخدم.
يوضّح المثال التالي كيفية التحقّق من الإنهاء بشكل صحيح:
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
}
...
}
...
}
إدارة المدة النشطة
أثناء ممارسة التمارين الرياضية، يمكن للتطبيق عرض المدة النشطة
للتمرين. يجب أن تكون التطبيقات و"خدمات الصحة" ووحدة التحكّم الدقيقة بالجهاز (MCU)، وهي المعالج المنخفض الطاقة المسؤول عن تتبُّع التمارين، متزامنة معًا، مع المدّة النشطة الحالية نفسها. للمساعدة في إدارة ذلك، تُرسِل "خدمات الصحة" ActiveDurationCheckpoint
يوفّر نقطة ربط يمكن للتطبيق من خلالها
بدء الموقّت.
بما أنّ المدة النشطة يتم إرسالها من وحدة التحكّم في الوسائط (MCU) ويمكن أن تستغرق وقتًا قصيرًا لوصولها إلى التطبيق، يحتوي العنصر ActiveDurationCheckpoint
على سمتَين:
-
activeDuration
: المدة التي كان فيها التمرين نشطًا -
time
: وقت احتساب المدة النشطة
لذلك، في التطبيق، يمكن حساب المدّة النشطة للتمرين
من ActiveDurationCheckpoint
باستخدام المعادلة التالية:
(now() - checkpoint.time) + checkpoint.activeDuration
ويعود ذلك إلى الاختلاف البسيط بين المدة النشطة التي يتم احتسابها في وحدة التحكّم في الوسائط (MCU) ووصولها إلى التطبيق. ويمكن استخدام ذلك لإنشاء مقياس زمني في التطبيق والمساعدة في التأكّد من توافق الموقّت في التطبيق تمامًا مع الوقت في "خدمات الصحة" ووحدة التحكّم في الوسائط (MCU).
إذا تم إيقاف التمرين مؤقتًا، ينتظر التطبيق إعادة تشغيل الموقّت في واجهة المستخدم
إلى أن يتجاوز الوقت المحسوب الوقت الذي تعرضه واجهة المستخدم حاليًا.
ويرجع ذلك إلى أنّ إشارة الإيقاف المؤقت تصل إلى خدمات الصحة ووحدة التحكّم في الوسائط بعد تأخّر بسيط. على سبيل المثال، إذا تم إيقاف التطبيق مؤقتًا عند t=10 ثوانٍ، قد لا تُرسِل Health
Services تحديث PAUSED
إلى التطبيق حتى t=10.2 ثانية.
العمل مع البيانات من ExerciseClient
يتم إرسال مقاييس أنواع البيانات التي سجّل تطبيقك طلبًا للحصول عليها في رسائل
ExerciseUpdate
.
لا تُرسِل وحدة المعالجة الرسائل إلا عندما تكون مفعَّلة أو عند بلوغ الحد الأقصى للفترة الزمنية التي يتم فيها إرسال التقارير، مثل كل 150 ثانية. لا تعتمد على معدل تكرار
ExerciseUpdate
لتحريك ساعة توقيت باستخدام
activeDuration
. يمكنك الاطّلاع على نموذج التمرين على GitHub للحصول على مثال على كيفية تنفيذ ساعة توقيت مستقلة.
عندما يبدأ أحد المستخدمين تمرينًا، يمكن إرسال رسائل ExerciseUpdate
بشكل متكرّر، مثلاً كل ثانية. عندما يبدأ المستخدم التمرين، قد يتم
إيقاف الشاشة. ويمكن أن ترسل "خدمات الصحة" البيانات بعد ذلك بمعدّل أقل، ولكن مع مواصلة أخذ عيّنات بالوتيرة
نفسها، لتجنُّب تنشيط المعالج الرئيسي. عندما ينظر المستخدم
إلى الشاشة، يتم إرسال أي بيانات في مرحلة تجميعها
على الفور إلى تطبيقك.
التحكّم في معدّل تجميع البيانات
في بعض السيناريوهات، قد تحتاج إلى التحكّم في معدّل تكرار تلقّي تطبيقك
لأنواع بيانات معيّنة عندما تكون الشاشة مطفأة. يسمح عنصر
BatchingMode
لتطبيقك بتجاهل السلوك التلقائي لعملية تجميع البيانات للحصول على عمليات إرسال data
بمعدل تكرار أعلى.
لضبط معدّل تجميع البيانات، يُرجى اتّباع الخطوات التالية:
تحقّق مما إذا كان الجهاز متوافقًا مع تعريف
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 }
حدِّد أنّ عنصر
ExerciseConfig
يجب أن يستخدمBatchingMode
معيّنًا، كما هو موضّح في مقتطف الرمز التالي.val config = ExerciseConfig( exerciseType = ExerciseType.WORKOUT, dataTypes = setOf( DataType.HEART_RATE_BPM, DataType.TOTAL_CALORIES ), // ... batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS) )
يمكنك اختياريًا ضبط
BatchingMode
ديناميكيًا أثناء التمرين، بدلاً من الحفاظ على سلوك مجمّع محدّد طوال مدّة التمرين:val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS) exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
لمحو القيمة المخصّصة لـ
BatchingMode
والعودة إلى السلوك التلقائي، أدخِل مجموعة فارغة فيexerciseClient.overrideBatchingModesForActiveExercise()
.
الطوابع الزمنية
تمثّل النقطة الزمنية لكل نقطة بيانات المدة التي انقضت منذ التمهيد للجهاز. لتحويل ذلك إلى طابع زمني، اتّبِع الخطوات التالية:
val bootInstant =
Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())
ويمكن بعد ذلك استخدام هذه القيمة مع getStartInstant()
أو getEndInstant()
لكل نقطة بيانات.
دقة البيانات
يمكن أن تحتوي بعض أنواع البيانات على معلومات دقة مرتبطة بكل نقطة بيانات.
يتم تمثيل ذلك في السمة accuracy
.
يمكن تعبئة صفوف HrAccuracy
وLocationAccuracy
لأنواع البيانات
HEART_RATE_BPM
وLOCATION
على التوالي. استخدِم السمة
accuracy
، حيثما كانت متوفّرة، لتحديد ما إذا كانت كل نقطة بيانات تتسم بدقة
كافية لتطبيقك.
تخزين البيانات وتحميلها
استخدِم Room للحفاظ على البيانات التي يتم تسليمها من Health Services. يتم تحميل البيانات في نهاية التمرين باستخدام آلية، مثل Work Manager. يضمن ذلك تأجيل طلبات الاتصال بالشبكة لتحميل البيانات إلى أن تنتهي عملية التمرين، مما يقلل من استهلاك الطاقة أثناء التمرين ويبسّط العمل.
قائمة التحقق من الدمج
قبل نشر تطبيقك الذي يستخدم ExerciseClient
في "الخدمات الصحية"، يمكنك الرجوع إلى قائمة التحقّق التالية لضمان تجنُّب تجربة المستخدم لبعض المشاكل الشائعة.
تأكَّد مما يلي:
- يفحص تطبيقك إمكانات نوع التمارين وإمكانات الجهاز في كل مرة يتم فيها تشغيل التطبيق. بهذه الطريقة، يمكنك رصد الحالات التي لا يتيح فيها جهاز أو تمرين معيّن استخدام أحد أنواع البيانات التي يحتاجها تطبيقك.
- يمكنك طلب الأذونات اللازمة والحفاظ عليها وتحديدها في
ملف البيان. قبل الاتصال بـ
prepareExerciseAsync()
، يُجري تطبيقك عمليات تأكيد على منح أذونات التشغيل. - يستخدم تطبيقك
getCurrentExerciseInfoAsync()
للتعامل مع الحالات التي:- يتم تتبُّع تمرين حاليًا، ويلغي تطبيقك التمرين السابق.
- أنهى تطبيق آخر التمرين. ويمكن أن يحدث ذلك عندما يعيد المستخدم فتح التطبيق، حيث تظهر له رسالة توضّح أنّ التمارين توقفت لأنّ تطبيقًا آخر تولى إكمالها.
- إذا كنت تستخدم بيانات
LOCATION
:- يحافظ تطبيقك على
ForegroundService
معforegroundServiceType
المرتبط به طوال مدة التمرين (بما في ذلك مكالمة الإعداد). - تأكَّد من تفعيل نظام تحديد المواقع العالمي (GPS) على الجهاز باستخدام
isProviderEnabled(LocationManager.GPS_PROVIDER)
، واطلب من المستخدم فتح إعدادات الموقع الجغرافي إذا لزم الأمر. - بالنسبة إلى حالات الاستخدام المتطلّبة التي يكون فيها تلقّي بيانات الموقع الجغرافي بوقت استجابة منخفض مهمًا جدًا، ننصحك بدمج موفِّر الموقع الجغرافي المدمج (FLP) واستخدام بياناته كحلّ أوّلي لتحديد الموقع الجغرافي. عندما تتوفّر معلومات موقع جغرافي أكثر ثباتًا من "خدمات الصحة"، استخدِمها بدلاً من FLP.
- يحافظ تطبيقك على
- إذا كان تطبيقك يتطلّب تحميل البيانات، يتم تأجيل أي طلبات للشبكة لتحميل البيانات إلى أن تنتهي الفترة الزمنية المحدّدة للاختبار. بخلاف ذلك، يُجري تطبيقك أي اتصالات ضرورية بالشبكة بشكل مقتصد طوال فترة الاختبار.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون لغة JavaScript غير مفعّلة.
- تعديلات البيانات السلبية
- خدمات الصحة على Wear OS
- بدء استخدام المربّعات