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

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

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

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

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

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

يسجّل نوع بيانات "الخطوات" في 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
    }
}

قراءة بيانات خطوات الجوّال

في نظام التشغيل 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

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

إذا كان تطبيقك يحتاج إلى قراءة الخطوات المسجّلة على الجهاز، أو إذا كان يعرض بيانات الخطوات مصنّفة حسب التطبيق أو الجهاز المصدر، يمكنك طلب البحث عن السجلات التي تكون فيها DataOrigin هي android. إذا كان تطبيقك يعرض تحديد المصدر لبيانات الخطوات، يجب تحديد مصدر البيانات من حزمة Android إلى الجهاز الحالي. يمكنك إجراء ذلك باستخدام تصنيف مثل "هاتفك"، أو استرداد اسم الجهاز باستخدام 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 تبلغ 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
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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