با Health Connect تجربیات خواب خود را توسعه دهید

اگر به دنبال ایجاد یک تجربه ردیابی خواب در برنامه خود هستید، می‌توانید از Health Connect برای انجام کارهایی مانند موارد زیر استفاده کنید:

  • جلسات خواب را بنویسید
  • داده‌های مرحله خواب را بنویسید
  • ثبت داده‌های خواب مانند ضربان قلب، اشباع اکسیژن و تعداد تنفس
  • خواندن داده‌های خواب از برنامه‌های دیگر

این راهنما نحوه ساخت این ویژگی‌های خواب را شرح می‌دهد و انواع داده‌ها، اجرای پس‌زمینه، مجوزها، گردش‌های کاری توصیه‌شده و بهترین شیوه‌ها را پوشش می‌دهد.

مرور کلی: ساخت یک ردیاب خواب جامع

شما می‌توانید با دنبال کردن این مراحل اصلی، یک تجربه جامع ردیابی خواب با استفاده از Health Connect ایجاد کنید:

  • پیاده‌سازی صحیح مجوزها بر اساس مجوزهای سلامت.
  • ضبط جلسات با استفاده از SleepSessionRecord
  • نوشتن انواع داده‌ها مانند مراحل خواب، ضربان قلب و اشباع اکسیژن به طور مداوم در طول جلسه.
  • مدیریت صحیح اجرای پس‌زمینه برای تأیید ضبط مداوم داده‌ها در طول شب.
  • خواندن داده‌های جلسه برای خلاصه‌سازی و تحلیل پس از خواب.

این گردش کار، قابلیت همکاری با سایر برنامه‌های Health Connect را فراهم می‌کند و دسترسی به داده‌ها تحت کنترل کاربر را تأیید می‌کند.

قبل از اینکه شروع کنی

قبل از پیاده‌سازی ویژگی‌های خواب:

مفاهیم کلیدی

Health Connect داده‌های خواب را با استفاده از چند مؤلفه اصلی نمایش می‌دهد. SleepSessionRecord به عنوان رکورد مرکزی خواب عمل می‌کند و شامل جزئیاتی مانند زمان شروع یا پایان و مراحل خواب است. در طول یک جلسه، انواع مختلفی از داده‌ها مانند HeartRateRecord یا OxygenSaturationRecord قابل ثبت هستند.

جلسات خواب

داده‌های خواب توسط SleepSessionRecord نمایش داده می‌شوند. هر رکورد موارد زیر را ذخیره می‌کند:

  • startTime
  • endTime
  • stages : فهرستی از SleepSessionRecord.Stage شامل خواب عمیق، سبک، REM و بیداری.
  • فراداده‌های اختیاری جلسه (عنوان، یادداشت‌ها)

برنامه‌ها ممکن است چندین نوع داده مرتبط با یک جلسه بنویسند.

انواع داده

انواع داده‌های رایج ثبت‌شده در طول یک جلسه خواب عبارتند از:

  • SleepSessionRecord : مدت زمان خواب و مراحل آن شامل خواب عمیق، سبک، REM و بیداری را ثبت می‌کند.
  • HeartRateRecord : ضربان قلب را در طول خواب ثبت می‌کند.
  • OxygenSaturationRecord : میزان اشباع اکسیژن (SpO2) را در طول خواب ثبت می‌کند.
  • RespiratoryRateRecord : نرخ تنفس را در طول خواب ثبت می‌کند.

هر نوع داده به صورت یک رکورد جداگانه ذخیره می‌شود.

ملاحظات توسعه

برنامه‌های ردیابی خواب اغلب نیاز دارند برای مدت طولانی، اغلب در پس‌زمینه، زمانی که صفحه نمایش خاموش است، اجرا شوند. هنگام ایجاد ویژگی‌های خواب، مهم است که نحوه مدیریت اجرای پس‌زمینه و درخواست مجوزهای لازم برای داده‌های خواب را در نظر بگیرید.

اجرای پس‌زمینه

برنامه‌های ردیابی خواب معمولاً در طول شب با صفحه نمایش خاموش اجرا می‌شوند. در این حالت، باید از موارد زیر استفاده کنید:

  • سرویس‌های پیش‌زمینه برای جمع‌آوری داده‌ها
  • WorkManager برای نوشتن یا همگام‌سازی معوق
  • استراتژی‌های دسته‌بندی برای نوشتن منظم رکوردها از داده‌های جزئی مانند ضربان قلب

با ثابت نگه داشتن شناسه جلسه در تمام نوشتن‌ها، پیوستگی را حفظ کنید.

مجوزها

برنامه شما قبل از خواندن یا نوشتن داده‌های خواب، باید مجوزهای مربوط به Health Connect را درخواست کند. برای مشاهده لیست کاملی از انواع داده‌ها، به انواع داده‌های Health Connect مراجعه کنید. مجوزهای رایج برای خواب شامل جلسات خواب و معیارهایی مانند ضربان قلب یا اشباع اکسیژن است.

دسترسی به حالت خواب توسط مجوزهای زیر محافظت می‌شود:

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

برای افزودن قابلیت خواب به برنامه خود، با درخواست مجوز برای نوع داده SleepSession شروع کنید.

برای نوشتن sleep باید مجوز زیر را اعلام کنید:

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

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

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

در زیر مثالی از نحوه درخواست مجوز برای یک جلسه خواب که شامل داده‌های ضربان قلب، اشباع اکسیژن و میزان تنفس است، نشان داده شده است:

پس از ایجاد یک نمونه کلاینت، برنامه شما باید از کاربر درخواست مجوز کند. کاربران باید بتوانند در هر زمانی مجوزها را اعطا یا رد کنند.

برای انجام این کار، مجموعه‌ای از مجوزها را برای انواع داده‌های مورد نیاز ایجاد کنید. مطمئن شوید که مجوزهای موجود در مجموعه ابتدا در مانیفست اندروید شما تعریف شده‌اند.

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(SleepSessionRecord::class),
  HealthPermission.getWritePermission(SleepSessionRecord::class),
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(OxygenSaturationRecord::class),
  HealthPermission.getWritePermission(OxygenSaturationRecord::class),
  HealthPermission.getReadPermission(RespiratoryRateRecord::class),
  HealthPermission.getWritePermission(RespiratoryRateRecord::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)
  }
}

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

یک جلسه خواب اجرا کنید

این بخش، گردش کار پیشنهادی برای ثبت داده‌های خواب را شرح می‌دهد.

برای هم‌تراز کردن انواع داده‌هایی مانند HeartRateRecord یا OxygenSaturationRecord با یک جلسه خواب، آنها را با مهرهای زمانی که بین startTime و endTime جلسه قرار می‌گیرند، ثبت کنید. Health Connect از شناسه جلسه برای پیوند دادن جلسات خواب با داده‌های جزئی استفاده نمی‌کند. در عوض، ارتباط از طریق فواصل زمانی همپوشانی ضمنی است. هنگام خواندن داده‌های خواب، می‌توانید از محدوده زمانی یک جلسه برای جستجوی انواع داده‌های مرتبط استفاده کنید، همانطور که در Reading sleep data نشان داده شده است.

یک جلسه بنویسید

در حالی که داده‌های جزئی مانند ضربان قلب را می‌توان در طول یک جلسه خواب ثبت کرد، خود SleepSessionRecord فقط باید پس از پایان جلسه، مثلاً زمانی که کاربر از خواب بیدار می‌شود، در Health Connect نوشته شود. این رکورد باید شامل startTime جلسه، endTime و لیستی از اشیاء SleepSessionRecord.Stage باشد که در طول جلسه ثبت شده‌اند، زیرا SleepSessionRecord نیاز دارد که endTime بعد از startTime باشد.

برای نوشتن یک جلسه خواب:

  1. یک شناسه رکورد مشتری منحصر به فرد ایجاد کنید.
  2. وقتی کاربر از خواب بیدار می‌شود، یا ردیابی خواب متوقف می‌شود، تمام مراحل خواب را جمع‌آوری کرده و یک SleepSessionRecord می‌سازد.
  3. با استفاده از insertRecords رکورد را درج کنید.

مثال:

val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)

val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(3600),
    endTime = sessionStartTime.plusSeconds(7200),
    stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(7200),
    endTime = sessionStartTime.plusSeconds(10800),
    stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages

val session = SleepSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    stages = stages,
    metadata = Metadata(clientRecordId = clientRecordId)
)

healthConnectClient.insertRecords(listOf(session))

خواندن داده‌های خواب

برنامه‌ها می‌توانند جلسات خواب و داده‌های مرتبط با آن را بخوانند تا فعالیت را خلاصه کنند، بینش‌های سلامتی ارائه دهند یا داده‌ها را با یک سرور خارجی همگام‌سازی کنند. به عنوان مثال، می‌توانید یک SleepSessionRecord بخوانید و سپس HeartRateRecord را که در همان بازه زمانی رخ داده است، جستجو کنید.

جلسه را با داده‌های مرتبط بخوانید

شما می‌توانید جلسات خواب را با استفاده از ReadRecordsRequest با نوع رکورد SleepSessionRecord که بر اساس یک محدوده زمانی فیلتر شده است، بخوانید. برای خواندن داده‌های مرتبط با یک جلسه معین، یک درخواست دوم برای نوع داده انتخاب شده، مانند HeartRateRecord ، ارسال کنید - که بر اساس startTime و endTime جلسه خواب فیلتر می‌شود.

مثال زیر نحوه خواندن جلسات خواب با داده‌های ضربان قلب مرتبط برای یک بازه زمانی مشخص را نشان می‌دهد:

suspend fun readSleepSessionsWithAssociatedData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (sleepRecord in response.records) {
        // Process each session
        val stages = sleepRecord.stages
        val notes = sleepRecord.notes

        // To read specific granular data (like heart rate) that occurred during
        // this session, use the session's startTime and endTime to filter
        // the request for that data type.
        val hrResponse = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(
                    sleepRecord.startTime,
                    sleepRecord.endTime
                )
            )
        )
        for (heartRateRecord in hrResponse.records) {
            for (sample in heartRateRecord.samples) {
                val bpm = sample.beatsPerMinute
            }
        }
    }
}

بهترین شیوه‌ها

برای بهبود قابلیت اطمینان داده‌ها و تجربه کاربری، این دستورالعمل‌ها را دنبال کنید:

  • فرکانس نوشتن
    • ردیابی فعال (پیش‌زمینه): برای ردیابی فعال خواب، داده‌ها را به محض در دسترس قرار گرفتن یا حداکثر با فاصله ۱۵ دقیقه بنویسید.
    • همگام‌سازی پس‌زمینه: از WorkManager برای نوشتن‌های معوق استفاده کنید. برای ایجاد تعادل بین داده‌های بلادرنگ و بهره‌وری باتری، یک فاصله ۱۵ دقیقه‌ای را در نظر بگیرید.
    • دسته‌بندی: هر رویداد حسگر را به صورت جداگانه ننویسید. درخواست‌های خود را به بخش‌های کوچک‌تر تقسیم کنید. Health Connect در هر درخواست نوشتن، تا ۱۰۰۰ رکورد را مدیریت می‌کند.
  • شناسه‌های جلسه را پایدار و منحصر به فرد نگه دارید: از شناسه‌های ثابت برای جلسات خود استفاده کنید. اگر یک جلسه ویرایش یا به‌روزرسانی شود، استفاده از همان شناسه مانع از آن می‌شود که به عنوان یک جلسه خواب جدید و جداگانه در نظر گرفته شود.
  • استفاده از دسته‌بندی برای انواع داده‌ها: برای کاهش سربار ورودی/خروجی و حفظ عمر باتری، نقاط داده خود را در یک فراخوانی insertRecords گروه‌بندی کنید، نه اینکه هر نقطه را جداگانه بنویسید.
  • از نوشتن داده‌های تکراری خودداری کنید: از شناسه‌های کلاینت استفاده کنید. هنگام ایجاد رکوردها، یک metadata.clientRecordId تنظیم کنید. Health Connect از این برای شناسایی رکوردهای منحصر به فرد استفاده می‌کند. اگر سعی کنید رکوردی را با clientRecordId موجود بنویسید، Health Connect به جای ایجاد یک رکورد جدید، رکورد تکراری را نادیده می‌گیرد یا رکورد موجود را به‌روزرسانی می‌کند. تنظیم metadata.clientRecordId موثرترین راه برای جلوگیری از تکرار در هنگام تلاش‌های مجدد همگام‌سازی یا نصب مجدد برنامه است.

    val record = RespiratoryRateRecord(
        rate = 16.0,
        time = time,
        zoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "respiratory_rate_20231030_1"
        )
    )
    
  • بررسی داده‌های موجود: قبل از همگام‌سازی، محدوده زمانی را بررسی کنید تا ببینید آیا رکوردهایی از برنامه شما از قبل وجود دارند یا خیر.

  • اطمینان حاصل کنید که مهرهای زمانی همپوشانی ندارند: تأیید کنید که یک جلسه جدید قبل از پایان جلسه قبلی شروع نشود. جلسات همپوشانی می‌توانند باعث ایجاد تداخل در داشبوردهای تناسب اندام و محاسبات خلاصه شوند.

  • دلایل منطقی و واضحی برای مجوز ارائه دهید: از جریان Permission.createIntent برای توضیح اینکه چرا برنامه شما به دسترسی به داده‌های سلامت نیاز دارد، مانند «برای تجزیه و تحلیل الگوهای خواب شما» استفاده کنید.

  • تست جلسات طولانی مدت: مصرف باتری را در طول جلساتی که چند ساعت طول می‌کشند، زیر نظر داشته باشید تا مطمئن شوید که فاصله زمانی بین جلسات و استفاده از حسگر، دستگاه را تخلیه نمی‌کند.

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

آزمایش

برای تأیید صحت داده‌ها و یک تجربه کاربری با کیفیت بالا، این استراتژی‌های آزمایش را دنبال کنید و به مستندات رسمی موارد استفاده برتر Test مراجعه کنید.

ابزارهای تأیید

  • جعبه ابزار Health Connect : از این برنامه همراه برای بررسی دستی رکوردها، حذف داده‌های آزمایشی و شبیه‌سازی تغییرات در پایگاه داده استفاده کنید. این بهترین راه برای تأیید صحت ذخیره رکوردهای شما است.
  • تست واحد با FakeHealthConnectClient : از کتابخانه تست برای تأیید نحوه مدیریت موارد خاص توسط برنامه شما، مانند لغو مجوز یا استثنائات API، بدون نیاز به دستگاه فیزیکی استفاده کنید.

چک لیست کیفیت

معماری معمولی

پیاده‌سازی ردیابی خواب معمولاً شامل موارد زیر است:

کامپوننت مدیریت می‌کند
کنترل‌کننده جلسه حالت جلسه
تایمر
منطق دسته بندی
کنترل‌کننده‌های انواع داده
جمع‌آوری داده‌ها
لایه مخزن (عملیات Health Connect را در بر می‌گیرد :) جلسه را وارد کنید
درج انواع داده
مراحل خواب را وارد می‌کند
خلاصه جلسات را بخوانید
لایه رابط کاربری (نمایشگرها): مدت زمان
انواع داده‌های زنده
تجسم مراحل خواب

عیب‌یابی

علامت علت احتمالی وضوح تصویر
انواع داده‌ی ناموجود (برای مثال، ضربان قلب) مجوزهای نوشتن وجود ندارد یا فیلترهای زمانی نادرست هستند. بررسی کنید که درخواست داده‌اید و کاربر مجوز نوع داده‌ی خاص را اعطا کرده است. تأیید کنید که ReadRecordsRequest شما از TimeRangeFilter استفاده می‌کند که با جلسه مطابقت دارد. به Permissions مراجعه کنید.
نوشتن در جلسه با شکست مواجه می‌شود مهرهای زمانی همپوشانی دارند. Health Connect ممکن است رکوردهایی را که با داده‌های موجود از همان برنامه همپوشانی دارند، رد کند. تأیید کنید که startTime یک جلسه جدید بعد از endTime جلسه قبلی باشد.
هیچ داده حسگری در طول خواب ثبت نشده است سرویس پیش‌زمینه از کار افتاده یا غیرفعال بود. برای جمع‌آوری داده‌های حسگر در طول شب، زمانی که صفحه نمایش خاموش است، می‌توانید از یک سرویس پیش‌زمینه با foregroundServiceType="health" استفاده کنید.
رکوردهای تکراری ظاهر می‌شوند شناسه clientRecordId موجود نیست یک clientRecordId منحصر به فرد در Metadata هر رکورد اختصاص دهید. این به Health Connect اجازه می‌دهد تا در صورت نوشتن دو بار داده‌های مشابه در طول تلاش مجدد همگام‌سازی، حذف داده‌های تکراری را انجام دهد. به بهترین شیوه‌ها مراجعه کنید.

مراحل اشکال‌زدایی رایج

  • بررسی وضعیت مجوزها: همیشه قبل از اقدام به عملیات خواندن یا نوشتن، تابع getPermissionStatus() را فراخوانی کنید. کاربران می‌توانند در هر زمانی مجوزها را در تنظیمات سیستم لغو کنند.
  • حالت اجرا را تأیید کنید: اگر برنامه شما در پس‌زمینه داده‌ها را جمع‌آوری نمی‌کند، تأیید کنید که مجوزهای صحیح را در AndroidManifest.xml خود اعلام کرده‌اید و کاربر برنامه را در حالت "Battery Restricted" قرار نداده است.