قراءة البيانات الأولية

يوضّح المثال التالي كيفية قراءة البيانات الأولية كجزء من سير العمل الشائع.

قراءة البيانات

يتيح Health Connect للتطبيقات قراءة البيانات من مستودع البيانات عندما يكون التطبيق نشطًا في المقدّمة والخلفية:

  • عمليات القراءة في المقدّمة: يمكنك عادةً قراءة البيانات من Health Connect عندما يكون تطبيقك نشطًا في المقدّمة. في هذه الحالات، يمكنك استخدام خدمة تعمل في المقدّمة لتنفيذ هذه العملية إذا وضع المستخدم أو النظام تطبيقك في الخلفية أثناء عملية القراءة.

  • عمليات القراءة في الخلفية: من خلال طلب إذن إضافي من المستخدم، يمكنك قراءة البيانات بعد أن يضع المستخدم أو النظام تطبيقك في الخلفية. يمكنك الاطّلاع على مثال كامل على القراءة في الخلفية.

يسجّل نوع بيانات "الخطوات" في Health Connect عدد الخطوات التي اتّخذها المستخدم بين القراءات. تمثّل أعداد الخطوات مقياسًا شائعًا على مستوى منصات الصحة واللياقة البدنية والعافية. يتيح لك تطبيق Health Connect قراءة بيانات عدد الخطوات وتعديلها.

لقراءة السجلات، أنشئ ReadRecordsRequest وقدّمه عند استدعاء readRecords.

يوضّح المثال التالي كيفية قراءة بيانات عدد الخطوات لمستخدم خلال فترة زمنية معيّنة. للاطّلاع على مثال موسّع يتضمّن SensorManager، راجِع دليل بيانات عدد الخطوات.

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        HeartRateRecord::class,
        timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
    )
)
response.records.forEach { record ->
    /* Process records */
}

يمكنك أيضًا قراءة بياناتك بشكل مجمّع باستخدام aggregate.

suspend fun readStepsAggregate(startTime: Instant, endTime: Instant): Long {
    val response = healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
    return response[StepsRecord.COUNT_TOTAL] ?: 0L
}

قراءة بيانات الخطوات على الأجهزة الجوّالة

في نظام التشغيل Android 14 (المستوى 34 لواجهة برمجة التطبيقات) والإصدار 20 أو الإصدارات الأحدث من حزمة SDK Extension، يوفّر تطبيق Health Connect ميزة احتساب الخطوات على الجهاز. إذا تم منح أي تطبيق إذن READ_STEPS، سيبدأ تطبيق Health Connect في تسجيل الخطوات من جهاز Android، وسيلاحظ المستخدمون أنّه تتم إضافة بيانات الخطوات تلقائيًا إلى إدخالات الخطوات في Health Connect.

للتحقّق من توفّر ميزة احتساب الخطوات على الجهاز فقط، تأكَّد من أنّ الجهاز يعمل بالإصدار Android 14 (مستوى واجهة برمجة التطبيقات 34) ويتضمّن على الأقل الإصدار 20 من إضافة حزمة تطوير البرامج (SDK):

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

إذا كان تطبيقك يقرأ عدد الخطوات المجمّع باستخدام aggregate ولا يفلتر حسب DataOrigin، سيتم تلقائيًا تضمين الخطوات المسجّلة على الجهاز فقط في الإجمالي، ولن تحتاج إلى إجراء أي تغييرات استعدادًا لتحديث يونيو 2026.

تغيير تحديد المصدر للخطوات التي يتم تتبّعها على الجهاز فقط

اعتبارًا من تحديث يونيو 2026، سيتم إسناد الخطوات التي يتم تتبُّعها تلقائيًا من خلال Health Connect إلى اسم حزمة اصطناعي (SPN)، مثل com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

في السابق، كانت الخطوات المضمّنة تُنسَب إلى اسم الحزمة android. تحتفظ بيانات الخطوات السابقة المسجّلة قبل يونيو 2026 باسم الحزمة android.

تكون أرقام التعريف الخاصة بموفّر الشبكة مخصّصة للجهاز ويتم تحديد نطاقها على أساس كل تطبيق على حدة لحماية خصوصية المستخدم:

  • مستقر: رقم تعريف الشبكة الخاصة (SPN) للجهاز الحالي مستقر لتطبيقك.
  • على مستوى التطبيق: تعرض التطبيقات المختلفة على الجهاز نفسه أرقام تعريف خدمة مختلفة لبيانات الخطوات على الجهاز فقط.

طلب خطوات على الجهاز فقط

بما أنّ أسماء SPN محدودة النطاق وخاصة بالجهاز، يجب عدم ترميز قيم أسماء SPN بشكل ثابت. بدلاً من ذلك، استخدِم واجهة برمجة التطبيقات getCurrentDeviceDataSource() لاسترداد SPN للجهاز الحالي.

بينما يتطلّب احتساب الخطوات على الجهاز فقط الإصدار 20 أو إصدارًا أحدث من حزمة تطوير البرامج (SDK)، تتوفّر واجهة برمجة التطبيقات getCurrentDeviceDataSource() على نظام التشغيل Android 14 (المستوى 34 لواجهة برمجة التطبيقات) مع الإصدار 11 أو إصدار أحدث من حزمة تطوير البرامج (SDK).

لا تتوفّر واجهة برمجة التطبيقات getCurrentDeviceDataSource() بعد في مكتبة Health Connect Jetpack. تستخدِم الأمثلة التالية واجهة برمجة تطبيقات إطار عمل Android بدلاً من ذلك:

import android.content.Context
import android.health.connect.HealthConnectManager

val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
val deviceDataSource = healthConnectManager?.getCurrentDeviceDataSource()
val currentDeviceSpn = deviceDataSource?.deviceDataOrigin?.packageName

إذا كان تطبيقك يحتاج إلى قراءة الخطوات المسجّلة على الجهاز فقط، أو إذا كان يعرض بيانات الخطوات مقسّمة حسب التطبيق أو الجهاز المصدر، عليك طلب البحث عن السجلات التي تكون فيها قيمة DataOrigin هي android أو تطابق رقم تعريف الجهاز في شبكة SPN. إذا كان تطبيقك يعرض معلومات تحديد المصدر لبيانات الخطوات، استخدِم metadata.device لتحديد الجهاز المصدر للسجلات الفردية. بالنسبة إلى الخطوات التي يتم تنفيذها على الجهاز فقط والمحدّدة برقم تعريف الشريك (SPN) في البيانات المجمّعة، يمكنك استخدام البيانات الوصفية للجهاز، مثل model أو manufacturer من DeviceDataSource، لتحديد المصدر، أو استخدام تصنيف عام، مثل "هاتفك"، للخطوات التي يتم تنفيذها على الجهاز فقط.

يوضّح المثال التالي كيفية قراءة بيانات عدد الخطوات المجمّعة على الجهاز فقط من خلال الفلترة حسب كل من android وSPN للجهاز الحالي:

import android.content.Context
import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.DataOrigin
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter
import java.time.Instant

suspend fun readDeviceStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    context: Context,
    startTime: Instant,
    endTime: Instant
) {
    // 1. Check if SDK Extension 11+ is available for getCurrentDeviceDataSource()
    val isDataSourceApiAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.U &&
            SdkExtensions.getExtensionVersion(Build.VERSION_CODES.U) >= 11

    try {
        val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)

        // 2. Safely fetch the package name only if API is available and data exists
        val currentDeviceSpn = if (isDataSourceApiAvailable) {
            healthConnectManager?.getCurrentDeviceDataSource()?.deviceDataOrigin?.packageName
        } else {
            null
        }

        val dataOriginFilters = mutableSetOf(DataOrigin("android"))

        // 3. Explicit null-safety check using .let
        currentDeviceSpn?.let {
            dataOriginFilters.add(DataOrigin(it))
        }

        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = dataOriginFilters
            )
        )

        val stepCount = response[StepsRecord.COUNT_TOTAL]

    } catch (e: Exception) {
        // Now this catch block only handles actual runtime exceptions, 
        // rather than Errors from missing methods.
    }
}

احتساب الخطوات على الجهاز فقط

  • استخدام أداة الاستشعار: يستخدم تطبيق Health Connect أداة الاستشعار TYPE_STEP_COUNTER من SensorManager. تم تحسين هذا المستشعر لتقليل استهلاك الطاقة، ما يجعله مثاليًا لتتبُّع الخطوات بشكل مستمر في الخلفية.
  • دقة البيانات: للحفاظ على عمر البطارية، يتم عادةً تجميع بيانات الخطوات وكتابتها في قاعدة بيانات Health Connect بمعدّل لا يزيد عن مرة واحدة في الدقيقة.
  • تحديد المصدر: إنّ الخطوات التي تسجّلها هذه الميزة قبل يونيو 2026 يتم تحديد مصدرها على أنّه اسم الحزمة android في DataOrigin. بعد هذا التاريخ، يتم تحديد مصدرها على أنّه شبكة شركاء معيّنة خاصة بالجهاز. اطّلِع على تغيير تحديد المصدر للخطوات التي يتم تنفيذها على الجهاز فقط.
  • التفعيل: لا تكون آلية احتساب الخطوات على الجهاز نشطة إلا عندما يمنح تطبيق واحد على الأقل على الجهاز إذن READ_STEPS ضمن Health Connect.

مثال على القراءة في الخلفية

لقراءة البيانات في الخلفية، يجب إدراج الإذن التالي في ملف البيان:

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

يوضّح المثال التالي كيفية قراءة بيانات عدد الخطوات في الخلفية لمستخدم خلال فترة زمنية معيّنة باستخدام WorkManager:

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

    override suspend fun doWork(): Result {
        val healthConnectClient = HealthConnectClient.getOrCreate(applicationContext)
        // Perform background read logic here
        return Result.success()
    }
}
fun enqueueBackgroundReadWorker(context: Context, healthConnectClient: HealthConnectClient) {
    if (healthConnectClient
            .features
            .getFeatureStatus(
                HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
            ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE
    ) {

        val periodicWorkRequest = PeriodicWorkRequestBuilder<ScheduleWorker>(1, TimeUnit.HOURS)
            .build()

        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "read_health_connect",
            ExistingPeriodicWorkPolicy.KEEP,
            periodicWorkRequest
        )
    }
}

تحتوي المَعلمة ReadRecordsRequest على قيمة تلقائية pageSize تبلغ 1000. إذا كان عدد السجلات في 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 بعد أن يعيد المستخدم تثبيته.

تنطبق بعض القيود على القراءة:

  • في Android 14 والإصدارات الأحدث

    • لا يوجد حدّ زمني سابق على قراءة التطبيق لبياناته.
    • حدّ 30 يومًا على تطبيق يقرأ بيانات أخرى
  • في Android 13 والإصدارات الأقدم

    • حدّ 30 يومًا لقراءة التطبيق أي بيانات

يمكن إزالة القيود من خلال طلب إذن القراءة.

لقراءة البيانات السابقة، عليك تحديد اسم الحزمة كعنصر 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
}

قراءة المعرّف الفريد للجهاز (UDI)

بالنسبة إلى السجلات الواردة من أجهزة طبية، يمكن لتطبيقات القراءة استخراج جزء معرّف الجهاز (DI) من رقم التعريف الفريد للجهاز (UDI) من البيانات الوصفية للجهاز. للحصول على إرشادات حول كيفية معالجة هذه المعلومات ومطابقتها مع قواعد البيانات التنظيمية، يُرجى الاطّلاع على دليل البيانات الوصفية.

قراءة البيانات الأقدم من 30 يومًا

بشكلٍ تلقائي، يمكن لجميع التطبيقات قراءة البيانات من Health Connect لمدة تصل إلى 30 يومًا قبل منح أي إذن لأول مرة.

إذا كنت بحاجة إلى تمديد أذونات القراءة إلى ما بعد أي من القيود التلقائية، اطلب PERMISSION_READ_HEALTH_DATA_HISTORY. في حال عدم توفّر هذا الإذن، ستؤدي محاولة قراءة السجلات التي مرّ عليها أكثر من 30 يومًا إلى حدوث خطأ.

سجلّ الأذونات لتطبيق محذوف

إذا حذف أحد المستخدمين تطبيقك، سيتم إلغاء جميع الأذونات، بما في ذلك إذن الوصول إلى السجلّ. إذا أعاد المستخدم تثبيت تطبيقك ومنح الإذن مرة أخرى، سيتم تطبيق القيود التلقائية نفسها، وسيتمكّن تطبيقك من قراءة البيانات من Health Connect لمدة تصل إلى 30 يومًا قبل هذا التاريخ الجديد.

على سبيل المثال، لنفترض أنّ المستخدم حذف تطبيقك في 10 أيار (مايو) 2023 ثم أعاد تثبيته في 15 أيار (مايو) 2023 ومنح أذونات القراءة. أقدم تاريخ يمكن لتطبيقك قراءة البيانات منه تلقائيًا هو 15 أبريل 2023.

التعامل مع الاستثناءات

يُصدر تطبيق Health Connect استثناءات عادية لعمليات الإنشاء والقراءة والتعديل والحذف عند حدوث مشكلة. يجب أن يرصد تطبيقك كل استثناء من هذه الاستثناءات ويتعامل معه على النحو المناسب.

تدرج كل طريقة في HealthConnectClient الاستثناءات التي يمكن طرحها. بشكل عام، يجب أن يتعامل تطبيقك مع الاستثناءات التالية:

الجدول 1: استثناءات Health Connect وأفضل الممارسات المقترَحة
استثناء الوصف أفضل الممارسات المقترَحة
IllegalStateException حدث أحد السيناريوهات التالية:

  • خدمة Health Connect غير متاحة.
  • الطلب ليس بنية صالحة. على سبيل المثال، طلب تجميعي في حِزم دورية يتم فيه استخدام عنصر Instant لـ timeRangeFilter.

عليك أولاً التعامل مع المشاكل المحتملة في المدخلات قبل تقديم طلب. من الأفضل تعيين قيم للمتغيّرات أو استخدامها كمَعلمات ضمن دالة مخصّصة بدلاً من استخدامها مباشرةً في طلباتك، وذلك حتى تتمكّن من تطبيق استراتيجيات معالجة الأخطاء.
IOException تحدث مشاكل عند قراءة البيانات وكتابتها من القرص. لتجنُّب هذه المشكلة، إليك بعض الاقتراحات:

  • احتفِظ بنسخة احتياطية من أي إدخال يقدّمه المستخدم.
  • القدرة على التعامل مع أي مشاكل تحدث أثناء عمليات الكتابة المجمّعة على سبيل المثال، تأكَّد من أنّ العملية تتجاوز المشكلة ونفِّذ العمليات المتبقية.
  • تطبيق استراتيجيات إعادة المحاولة والتراجع للتعامل مع مشاكل الطلبات

RemoteException حدثت أخطاء في الخدمة الأساسية التي يتصل بها حزمة تطوير البرامج (SDK) أو أثناء التواصل معها.

على سبيل المثال، يحاول تطبيقك حذف سجلّ يتضمّن uid معيّنًا. ومع ذلك، يتم طرح الاستثناء بعد أن يكتشف التطبيق عند التحقّق من الخدمة الأساسية أنّ السجلّ غير متوفّر.
لتجنُّب هذه المشكلة، إليك بعض الاقتراحات:

  • إجراء عمليات مزامنة منتظمة بين مستودع بيانات تطبيقك وHealth Connect
  • تطبيق استراتيجيات إعادة المحاولة والتراجع للتعامل مع مشاكل الطلبات

SecurityException تحدث مشاكل عندما تتطلّب الطلبات أذونات لم يتم منحها. لتجنُّب ذلك، تأكَّد من الإفصاح عن استخدام أنواع بيانات Health Connect في تطبيقك المنشور، ويجب أيضًا الإفصاح عن أذونات Health Connect في ملف البيان وفي نشاطك.