یک تمرین را با ExerciseClient ضبط کنید

سرویس‌های سلامت از طریق ExerciseClient از برنامه‌های ورزشی پشتیبانی می‌کنند. با ExerciseClient ، برنامه شما می‌تواند زمان انجام یک تمرین را کنترل کند، اهداف ورزشی اضافه کند و به‌روزرسانی‌هایی در مورد وضعیت تمرین، رویدادهای ورزشی یا سایر معیارها دریافت کند. برای اطلاعات بیشتر، به لیست کامل انواع تمریناتی که سرویس‌های سلامت پشتیبانی می‌کنند، مراجعه کنید.

نمونه تمرین را در گیت‌هاب ببینید.

وابستگی‌ها را اضافه کنید

برای افزودن وابستگی به سرویس‌های بهداشتی، باید مخزن Google Maven را به پروژه خود اضافه کنید. برای اطلاعات بیشتر، به مخزن Google's Maven مراجعه کنید.

سپس، در فایل build.gradle در سطح ماژول، وابستگی زیر را اضافه کنید:

شیار

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

کاتلین

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

ساختار برنامه

هنگام ساخت یک برنامه ورزشی با خدمات درمانی، از ساختار برنامه زیر استفاده کنید:

  • صفحات نمایش و ناوبری خود را در یک فعالیت اصلی نگه دارید.
  • وضعیت تمرین، داده‌های حسگر، فعالیت مداوم و داده‌ها را با یک سرویس پیش‌زمینه مدیریت کنید.
  • داده‌ها را با Room ذخیره کنید و از WorkManager برای آپلود داده‌ها استفاده کنید.

هنگام آماده شدن برای تمرین و در طول تمرین، ممکن است فعالیت شما به دلایل مختلف متوقف شود. کاربر ممکن است به برنامه دیگری تغییر کند یا به صفحه ساعت بازگردد. سیستم ممکن است چیزی را در بالای فعالیت شما نمایش دهد، یا ممکن است صفحه نمایش پس از یک دوره عدم فعالیت خاموش شود. از یک ForegroundService که به طور مداوم در حال اجرا است به همراه ExerciseClient برای اطمینان از عملکرد صحیح در کل تمرین استفاده کنید.

استفاده از ForegroundService به شما امکان می‌دهد از API مربوط به فعالیت در حال انجام (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

برای دریافت به‌روزرسانی‌های وضعیت ورزش ثبت‌نام کنید

به‌روزرسانی‌های تمرین به یک شنونده (listener) ارسال می‌شوند. برنامه شما فقط می‌تواند یک شنونده را در یک زمان ثبت کند. شنونده خود را قبل از شروع تمرین، همانطور که در مثال زیر نشان داده شده است، تنظیم کنید. شنونده شما فقط به‌روزرسانی‌های مربوط به تمرین‌هایی را که برنامه شما دارد، دریافت می‌کند.

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 یا ضربان قلب، ممکن است مدت زمان کوتاهی برای گرم شدن نیاز داشته باشند، یا کاربر ممکن است بخواهد قبل از شروع تمرین، داده‌های خود را مشاهده کند. متد اختیاری prepareExerciseAsync() به این حسگرها اجازه می‌دهد تا گرم شوند و داده‌ها بدون شروع تایمر برای تمرین دریافت شوند. activeDuration تحت تأثیر این زمان آماده‌سازی قرار نمی‌گیرد.

قبل از فراخوانی تابع prepareExerciseAsync() ، موارد زیر را بررسی کنید:

  • تنظیمات موقعیت مکانی در سطح پلتفرم را بررسی کنید. کاربر این تنظیمات را در منوی تنظیمات اصلی کنترل می‌کند؛ این تنظیمات با بررسی مجوزهای سطح برنامه متفاوت است.

    اگر این تنظیم غیرفعال است، به کاربر اطلاع دهید که دسترسی به موقعیت مکانی را رد کرده است و اگر برنامه شما به موقعیت مکانی نیاز دارد، از او بخواهید آن را فعال کند.

  • تأیید کنید که برنامه شما مجوزهای زمان اجرا برای حسگرهای بدن (سطح API 35 یا پایین‌تر) یا ضربان قلب (سطح API 36+)، تشخیص فعالیت و موقعیت مکانی دقیق را دارد. برای مجوزهای از دست رفته، با ارائه زمینه کافی، از کاربر مجوزهای زمان اجرا را درخواست کنید. اگر کاربر مجوز خاصی را اعطا نکرد، انواع داده‌های مرتبط با آن مجوز را از فراخوانی تابع prepareExerciseAsync() حذف کنید. اگر نه حسگر بدن (ضربان قلب در سطح API 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 قرار دارد، به‌روزرسانی‌های مربوط به در دسترس بودن حسگرها از طریق onAvailabilityChanged() در ExerciseUpdateCallback ارائه می‌شوند. این اطلاعات سپس می‌تواند در اختیار کاربر قرار گیرد تا بتواند تصمیم بگیرد که آیا تمرین خود را شروع کند یا خیر.

تمرین را شروع کنید

وقتی می‌خواهید یک تمرین را شروع کنید، یک ExerciseConfig ایجاد کنید تا نوع تمرین، انواع داده‌هایی که می‌خواهید برای آنها معیار دریافت کنید و هرگونه هدف یا نقطه عطف تمرین را پیکربندی کنید.

اهداف تمرینی شامل یک DataType و یک شرط (condition) هستند. اهداف تمرینی، اهدافی یک‌باره هستند که با برآورده شدن یک شرط، مثلاً زمانی که کاربر مسافت مشخصی را می‌دود، فعال می‌شوند. همچنین می‌توان یک نقطه عطف تمرینی (exercise point) تعیین کرد. نقاط عطف تمرینی می‌توانند چندین بار فعال شوند، مثلاً هر بار که کاربر از یک نقطه خاص، مسافت تعیین‌شده خود را طی می‌کند.

نمونه زیر نحوه ایجاد یک هدف از هر نوع را نشان می‌دهد:

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 منعکس شود. این موضوع به ویژه در مورد وضعیت‌های رابط کاربری اهمیت دارد. اگر کاربر pause را فشار دهد، دکمه pause را غیرفعال کنید و pauseExerciseAsync() را روی سرویس‌های سلامت فراخوانی کنید. با استفاده از ExerciseUpdate.exerciseStateInfo.state منتظر بمانید تا سرویس‌های سلامت به وضعیت متوقف شده برسند و سپس دکمه را به حالت از سرگیری تغییر دهید. دلیل این امر این است که به‌روزرسانی‌های وضعیت سرویس‌های سلامت می‌توانند بیشتر از فشار دادن دکمه طول بکشند، بنابراین اگر تمام تغییرات رابط کاربری را به فشار دادن دکمه مرتبط کنید، رابط کاربری می‌تواند با وضعیت سرویس‌های سلامت از همگام‌سازی خارج شود.

این نکته را در موقعیت‌های زیر به خاطر داشته باشید:

  • مکث خودکار فعال است: تمرین می‌تواند بدون تعامل کاربر متوقف یا شروع شود.
  • برنامه دیگری تمرین را شروع می‌کند: ممکن است تمرین شما بدون تعامل با کاربر خاتمه یابد.

اگر فعالیت برنامه شما توسط برنامه دیگری خاتمه یابد، برنامه شما باید به طور مناسب این خاتمه را مدیریت کند:

  • وضعیت تمرین جزئی را ذخیره کنید تا پیشرفت کاربر پاک نشود.
  • آیکون «فعالیت در حال انجام» را حذف کنید و یک اعلان برای کاربر ارسال کنید تا به او اطلاع دهید که تمرینش توسط برنامه دیگری پایان یافته است.

همچنین، حالتی را که مجوزها در طول یک تمرین در حال انجام لغو می‌شوند، مدیریت کنید. این مورد با استفاده از حالت 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 هماهنگ است، کمک کند.

اگر تمرین متوقف شود، برنامه منتظر می‌ماند تا تایمر را در رابط کاربری مجدداً راه‌اندازی کند تا زمان محاسبه‌شده از آنچه رابط کاربری نمایش می‌دهد، فراتر رود. دلیل این امر این است که سیگنال مکث با کمی تأخیر به سرویس‌های سلامت و MCU می‌رسد. برای مثال، اگر برنامه در زمان t=10 ثانیه متوقف شود، سرویس‌های سلامت ممکن است به‌روزرسانی PAUSED را تا زمان t=10.2 ثانیه به برنامه ارائه ندهند.

کار با داده‌ها از ExerciseClient

معیارهای مربوط به انواع داده‌هایی که برنامه شما برای آنها ثبت نام کرده است، در پیام‌های ExerciseUpdate ارائه می‌شوند.

پردازنده فقط زمانی که بیدار است یا زمانی که به حداکثر دوره گزارش‌دهی، مثلاً هر ۱۵۰ ثانیه، رسیده باشد، پیام‌ها را ارسال می‌کند. برای پیشبرد زمان‌سنج با activeDuration به فرکانس ExerciseUpdate تکیه نکنید. برای مثالی از نحوه پیاده‌سازی یک زمان‌سنج مستقل، به نمونه Exercise در GitHub مراجعه کنید.

وقتی کاربر تمرینی را شروع می‌کند، پیام‌های ExerciseUpdate می‌توانند مرتباً، مثلاً هر ثانیه، ارسال شوند. با شروع تمرین توسط کاربر، ممکن است صفحه نمایش خاموش شود. سپس سرویس‌های سلامت می‌توانند داده‌ها را کمتر ارسال کنند، اما همچنان با همان فرکانس نمونه‌برداری شوند تا از بیدار شدن پردازنده اصلی جلوگیری شود. وقتی کاربر به صفحه نمایش نگاه می‌کند، هر داده‌ای که در حال پردازش و دسته‌بندی است، بلافاصله به برنامه شما ارسال می‌شود.

نرخ بچینگ را کنترل کنید

در برخی سناریوها، ممکن است بخواهید تعداد دفعاتی که برنامه شما انواع خاصی از داده‌ها را در حالی که صفحه نمایش خاموش است دریافت می‌کند، کنترل کنید. یک شیء 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 سفارشی‌شده و بازگشت به رفتار پیش‌فرض، یک مجموعه خالی به exerciseClient.overrideBatchingModesForActiveExercise() ارسال کنید.

مهرهای زمانی

نقطه زمانی هر نقطه داده، مدت زمان از زمان بوت شدن دستگاه را نشان می‌دهد. برای تبدیل این به یک برچسب زمانی، موارد زیر را انجام دهید:

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

این مقدار می‌تواند سپس با getStartInstant() یا getEndInstant() برای هر نقطه داده استفاده شود.

دقت داده‌ها

برخی از انواع داده‌ها می‌توانند اطلاعات مربوط به دقت را با هر نقطه داده مرتبط کنند. این اطلاعات در ویژگی accuracy نمایش داده می‌شود.

کلاس‌های HrAccuracy و LocationAccuracy را می‌توان به ترتیب برای انواع داده HEART_RATE_BPM و LOCATION پر کرد. در صورت وجود، از ویژگی accuracy برای تعیین اینکه آیا هر نقطه داده از دقت کافی برای برنامه شما برخوردار است یا خیر، استفاده کنید.

ذخیره و بارگذاری داده‌ها

از Room برای ذخیره داده‌های دریافتی از سرویس‌های بهداشتی استفاده کنید. آپلود داده‌ها در پایان تمرین با استفاده از مکانیزمی مانند Work Manager انجام می‌شود. این به تأیید این نکته کمک می‌کند که درخواست‌های شبکه برای آپلود داده‌ها تا پایان تمرین به تعویق افتاده و مصرف برق در طول تمرین به حداقل رسیده و کار ساده‌تر شود.

چک لیست ادغام

قبل از انتشار برنامه‌ای که از ExerciseClient خدمات درمانی استفاده می‌کند، برای اطمینان از اینکه تجربه کاربری شما از برخی مشکلات رایج جلوگیری می‌کند، به چک لیست زیر مراجعه کنید. تأیید کنید که:

  • برنامه شما هر بار که اجرا می‌شود، قابلیت‌های نوع تمرین و قابلیت‌های دستگاه را بررسی می‌کند . به این ترتیب، می‌توانید تشخیص دهید که چه زمانی یک دستگاه یا تمرین خاص از یکی از انواع داده‌های مورد نیاز برنامه شما پشتیبانی نمی‌کند.
  • شما مجوزهای لازم را درخواست و نگهداری می‌کنید و این موارد را در فایل مانیفست خود مشخص می‌کنید. قبل از فراخوانی prepareExerciseAsync() ، برنامه شما تأیید می‌کند که مجوزهای زمان اجرا اعطا شده‌اند.
  • برنامه شما از getCurrentExerciseInfoAsync() برای مدیریت مواردی که :
    • یک تمرین از قبل ردیابی می‌شود و برنامه شما تمرین قبلی را لغو می‌کند.
    • برنامه دیگری تمرین شما را متوقف کرده است. این اتفاق ممکن است زمانی رخ دهد که کاربر برنامه را دوباره باز کند و با پیامی مواجه شود که توضیح می‌دهد تمرین به دلیل به عهده گرفتن کنترل توسط برنامه دیگری متوقف شده است.
  • اگر از داده‌های LOCATION استفاده می‌کنید:
    • برنامه شما در طول مدت تمرین (از جمله فراخوانی آماده‌سازی) یک ForegroundService با foregroundServiceType مربوطه را نگهداری می‌کند.
    • با استفاده از isProviderEnabled(LocationManager.GPS_PROVIDER) بررسی کنید که GPS روی دستگاه فعال باشد و در صورت لزوم از کاربر بخواهد تنظیمات مکان را باز کند.
    • برای موارد استفاده‌ی دشوار، که دریافت داده‌های مکانی با تأخیر کم از اهمیت بالایی برخوردار است، ادغام ارائه‌دهنده‌ی مکانی ترکیبی (FLP) و استفاده از داده‌های آن به عنوان یک راه‌حل اولیه‌ی مکانی را در نظر بگیرید. هنگامی که اطلاعات مکانی پایدارتری از خدمات درمانی در دسترس است، به جای FLP از آن استفاده کنید.
  • اگر برنامه شما نیاز به آپلود داده داشته باشد، هرگونه فراخوانی شبکه برای آپلود داده تا پایان تمرین به تعویق می‌افتد. در غیر این صورت، در طول تمرین، برنامه شما هرگونه فراخوانی شبکه لازم را به طور محدود انجام می‌دهد.
{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}