خواندن داده های خام

مثال زیر نحوه خواندن داده‌های خام را به عنوان بخشی از گردش کار رایج نشان می‌دهد.

خواندن داده‌ها

Health Connect به برنامه‌ها اجازه می‌دهد تا داده‌ها را از پایگاه داده بخوانند، چه در پیش‌زمینه و چه در پس‌زمینه:

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

  • خواندن پس‌زمینه : با درخواست مجوز اضافی از کاربر، می‌توانید داده‌ها را پس از قرار دادن برنامه در پس‌زمینه توسط کاربر یا سیستم، بخوانید. مثال کامل خواندن پس‌زمینه را ببینید.

نوع داده Steps در Health Connect تعداد گام‌هایی را که کاربر بین قرائت‌ها برداشته است، ثبت می‌کند. تعداد گام‌ها نشان‌دهنده یک معیار مشترک در پلتفرم‌های سلامت، تناسب اندام و تندرستی است. Health Connect به شما امکان می‌دهد داده‌های تعداد گام‌ها را بخوانید و بنویسید.

برای خواندن رکوردها، یک ReadRecordsRequest ایجاد کنید و هنگام فراخوانی readRecords آن را ارائه دهید.

مثال زیر نحوه خواندن داده‌های شمارش گام برای یک کاربر در یک زمان مشخص را نشان می‌دهد. برای مثالی جامع‌تر با SensorManager ، به راهنمای داده‌های شمارش گام مراجعه کنید.

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.readRecords(
            ReadRecordsRequest(
                StepsRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        for (record in response.records) {
            // Process each record
        }
    } catch (e: Exception) {
        // Run error handling here
    }
}

همچنین می‌توانید با استفاده از aggregate داده‌های خود را به صورت تجمیع‌شده بخوانید.

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

مراحل موبایل را بخوانید

با اندروید ۱۴ (سطح API ۳۴) و افزونه SDK نسخه ۲۰ یا بالاتر، Health Connect امکان شمارش گام‌ها را روی دستگاه فراهم می‌کند. اگر به هر برنامه‌ای مجوز READ_STEPS اعطا شده باشد، Health Connect شروع به ثبت گام‌ها از دستگاه مبتنی بر اندروید می‌کند و کاربران می‌توانند داده‌های گام‌ها را که به طور خودکار به ورودی‌های Health Connect Steps اضافه می‌شوند، مشاهده کنند.

برای بررسی اینکه آیا شمارش گام روی دستگاه در دسترس است، باید تأیید کنید که دستگاه از اندروید ۱۴ (سطح API ۳۴) استفاده می‌کند و حداقل نسخه ۲۰ افزونه SDK را دارد. می‌توانید از کد زیر استفاده کنید:

val isStepTrackingAvailable =
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20

تعداد گام‌های ثبت‌شده توسط اپلیکیشن Health Connect در DataOrigin روی نام بسته‌ی android تنظیم شده است. اگر برنامه‌ی شما صرفاً تعداد گام‌های جمع‌آوری‌شده را با استفاده aggregate می‌خواند و با DataOrigin فیلتر نمی‌کند، گام‌های ثبت‌شده روی دستگاه به‌طور خودکار در مجموع گنجانده می‌شوند.

اگر برنامه شما نیاز به خواندن مراحل روی دستگاه دارد، یا اگر داده‌های مرحله‌ای را بر اساس برنامه یا دستگاه مبدا نمایش می‌دهد، می‌توانید رکوردهایی را که DataOrigin مربوط به android است، جستجو کنید. اگر برنامه شما برای داده‌های مرحله‌ای، نسبتی نشان می‌دهد، باید داده‌ها را از بسته اندروید به دستگاه فعلی نسبت دهید. می‌توانید این کار را با استفاده از برچسبی مانند "Your phone" یا بازیابی نام دستگاه با استفاده از Settings.Global.getString(resolver, Settings.Global.DEVICE_NAME) یا بررسی فیلد Device در فراداده رکورد انجام دهید.

مثال زیر نحوه خواندن داده‌های جمع‌آوری‌شده از تعداد گام‌های موبایل را با فیلتر کردن مبدا داده‌های android نشان می‌دهد:

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = setOf(DataOrigin("android"))
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

شمارش گام روی دستگاه

بررسی عمیق‌تر ویژگی شمارش گام روی دستگاه:

  • کاربرد حسگر : Health Connect از حسگر TYPE_STEP_COUNTER از SensorManager استفاده می‌کند. این حسگر برای مصرف کم انرژی بهینه شده است و آن را برای ردیابی مداوم گام‌ها در پس‌زمینه ایده‌آل می‌کند.
  • جزئیات داده‌ها : برای صرفه‌جویی در مصرف باتری، داده‌های مرحله معمولاً دسته‌بندی شده و حداکثر یک بار در دقیقه در پایگاه داده Health Connect نوشته می‌شوند.
  • انتساب : همانطور که قبلاً ذکر شد، تمام مراحل ثبت شده توسط این ویژگی روی دستگاه به نام بسته android در DataOrigin نسبت داده می‌شوند.
  • فعال‌سازی : مکانیزم شمارش گام روی دستگاه تنها زمانی فعال است که حداقل به یک برنامه روی دستگاه، مجوز READ_STEPS در Health Connect اعطا شده باشد.

مثال خواندن پس‌زمینه

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

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

مثال زیر نحوه خواندن داده‌های شمارش گام در پس‌زمینه برای یک کاربر در یک زمان مشخص با استفاده از WorkManager را نشان می‌دهد:

class ScheduleWorker(private val appContext: Context, workerParams: WorkerParameters):
    CoroutineWorker(appContext, workerParams) {

    override suspend fun doWork(): Result {
        // Read data and process it.
        ...

        // Return success indicating successful data retrieval
        return Result.success()
    }
}

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

    // Check if necessary permission is granted
    val grantedPermissions = healthConnectClient.permissionController.getGrantedPermissions()

    if (PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND !in grantedPermissions) {
        // Perform read in foreground
        ...
    } else {
        // Schedule the periodic work request in background
        val periodicWorkRequest = PeriodicWorkRequestBuilder<ScheduleWorker>(1, TimeUnit.HOURS)
            .build()

        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "read_health_connect",
            ExistingPeriodicWorkPolicy.KEEP,
            periodicWorkRequest
        )
    }
} else {
  // Background reading is not available, perform read in foreground
  ...
}

پارامتر ReadRecordsRequest دارای مقدار پیش‌فرض pageSize برابر با ۱۰۰۰ است. اگر تعداد رکوردهای موجود در یک readResponse از pageSize درخواست بیشتر شود، باید با استفاده از pageToken تمام صفحات پاسخ را پیمایش کنید تا تمام رکوردها را بازیابی کنید. با این حال، مراقب باشید که از نگرانی‌های مربوط به محدود کردن سرعت جلوگیری کنید.

مثال خواندن pageToken

توصیه می‌شود از pageToken برای خواندن رکوردها و بازیابی تمام داده‌های موجود از دوره زمانی درخواستی استفاده کنید.

مثال زیر نحوه خواندن همه رکوردها را تا زمانی که همه توکن‌های صفحه تمام شوند، نشان می‌دهد:

val type = HeartRateRecord::class
val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofDays(7))

try {
    var pageToken: String? = null
    do {
        val readResponse =
            healthConnectClient.readRecords(
                ReadRecordsRequest(
                    recordType = type,
                    timeRangeFilter = TimeRangeFilter.between(
                        startTime,
                        endTime
                    ),
                    pageToken = pageToken
                )
            )
        val records = readResponse.records
        // Do something with records
        pageToken = readResponse.pageToken
    } while (pageToken != null)
} catch (quotaError: IllegalStateException) {
    // Backoff
}

برای کسب اطلاعات در مورد بهترین شیوه‌ها هنگام خواندن مجموعه داده‌های بزرگ، به «برنامه‌ریزی برای جلوگیری از محدود کردن نرخ» مراجعه کنید.

خواندن داده‌های قبلاً نوشته شده

اگر برنامه‌ای قبلاً سوابقی را در Health Connect ثبت کرده باشد، آن برنامه می‌تواند داده‌های تاریخی را بخواند. این برای سناریوهایی کاربرد دارد که در آن‌ها برنامه پس از نصب مجدد توسط کاربر، نیاز به همگام‌سازی مجدد با Health Connect دارد.

برخی محدودیت‌های خواندن اعمال می‌شود:

  • برای اندروید ۱۴ و بالاتر

    • هیچ محدودیت تاریخی برای خواندن داده‌های خود توسط یک برنامه وجود ندارد.
    • محدودیت ۳۰ روزه برای خواندن سایر داده‌ها توسط یک برنامه.
  • برای اندروید ۱۳ و پایین‌تر

    • محدودیت ۳۰ روزه برای خواندن هرگونه داده توسط برنامه.

این محدودیت‌ها را می‌توان با درخواست مجوز خواندن (Read permission) حذف کرد.

برای خواندن داده‌های تاریخی، باید نام بسته را به عنوان یک شیء DataOrigin در پارامتر dataOriginFilter از ReadRecordsRequest خود مشخص کنید.

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

try {
    val response =  healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = HeartRateRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
            dataOriginFilter = setOf(DataOrigin("com.my.package.name"))
        )
    )
    for (record in response.records) {
        // Process each record
    }
} catch (e: Exception) {
    // Run error handling here
}

خواندن داده‌های قدیمی‌تر از ۳۰ روز

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

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

تاریخچه مجوزها برای یک برنامه حذف شده

اگر کاربری برنامه شما را حذف کند، تمام مجوزها، از جمله مجوز تاریخچه، لغو می‌شوند. اگر کاربر برنامه شما را دوباره نصب کند و دوباره مجوز بدهد، همان محدودیت‌های پیش‌فرض اعمال می‌شود و برنامه شما می‌تواند داده‌ها را از Health Connect تا 30 روز قبل از آن تاریخ جدید بخواند.

برای مثال، فرض کنید کاربر برنامه شما را در 10 می 2023 حذف می‌کند و سپس در 15 می 2023 برنامه را دوباره نصب می‌کند و مجوزهای خواندن را اعطا می‌کند. زودترین تاریخی که برنامه شما اکنون می‌تواند داده‌ها را به طور پیش‌فرض از آن بخواند ، 15 آوریل 2023 است.

مدیریت استثنائات

Health Connect هنگام مواجهه با مشکل، استثنائات استانداردی را برای عملیات CRUD ایجاد می‌کند. برنامه شما باید هر یک از این استثنائات را به طور مناسب دریافت و مدیریت کند.

هر متد در HealthConnectClient استثنائاتی را که می‌توانند رخ دهند، فهرست می‌کند. به طور کلی، برنامه شما باید استثنائات زیر را مدیریت کند:

جدول ۱: استثنائات Health Connect و بهترین شیوه‌های پیشنهادی
استثنا توضیحات بهترین شیوه توصیه شده
IllegalStateException یکی از سناریوهای زیر رخ داده است:

  • سرویس Health Connect در دسترس نیست.
  • درخواست دارای ساختار معتبری نیست. برای مثال، یک درخواست تجمیعی در بازه‌های زمانی متناوب که در آن از یک شیء Instant برای timeRangeFilter استفاده شده است.

قبل از انجام درخواست، ابتدا مشکلات احتمالی مربوط به ورودی‌ها را برطرف کنید. ترجیحاً، به جای استفاده مستقیم از متغیرها در درخواست‌های خود، مقادیری را به آنها اختصاص دهید یا از آنها به عنوان پارامتر در یک تابع سفارشی استفاده کنید تا بتوانید استراتژی‌های مدیریت خطا را اعمال کنید.
IOException هنگام خواندن و نوشتن داده‌ها از دیسک، مشکلاتی وجود دارد. برای جلوگیری از این مشکل، چند پیشنهاد ارائه می‌شود:

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

RemoteException خطاهایی در داخل یا در ارتباط با سرویس اصلی که SDK به آن متصل می‌شود، رخ داده است.

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

  • همگام‌سازی‌های منظمی بین پایگاه داده برنامه خود و Health Connect انجام دهید.
  • برای رسیدگی به مشکلات درخواست، از استراتژی‌های تلاش مجدد و عقب‌نشینی استفاده کنید.

SecurityException وقتی درخواست‌ها نیاز به مجوزهایی دارند که اعطا نمی‌شوند، مشکلاتی پیش می‌آید. برای جلوگیری از این، مطمئن شوید که از انواع داده Health Connect برای برنامه منتشر شده خود استفاده کرده‌اید . همچنین، باید مجوزهای Health Connect را در فایل مانیفست و در activity خود اعلام کنید.