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

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

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

يسمح 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
    }
}

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

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

<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 في ملف البيان وفي نشاطك.