مراقبة البيانات في الخلفية

تناسب تحديثات البيانات السلبية للتطبيقات التي تحتاج إلى مراقبة بيانات "الخدمات الصحية" في الخلفية. وهي مخصصة لحالات الاستخدام التي تمتد لساعات أو أيام أو أكثر من ذلك. إذا كنت بحاجة إلى تخزين أو معالجة البيانات الصحية أثناء عدم تشغيل تطبيقك وعدم مشاركة المستخدم بشكل صريح في ممارسة التمارين، استخدِم البرنامج السلبي لخدمة Health Service.

للحصول على أمثلة حول الاستخدام السلبي للبيانات، يُرجى الاطّلاع على نموذجي البيانات السلبية والأهداف السلبية على GitHub.

إضافة التبعيات

لإضافة تبعية على "الخدمات الصحية"، يجب إضافة مستودع Google Maven إلى مشروعك. لمزيد من المعلومات، راجِع مستودع Maven من Google.

في ملف build.gradle على مستوى الوحدة، أضِف التبعية التالية:

رائع

dependencies {
    implementation "androidx.health:health-services-client:1.1.0-alpha02"
}

Kotlin

dependencies {
    implementation("androidx.health:health-services-client:1.1.0-alpha02")
}

التحقّق من الإمكانات

قبل التسجيل للحصول على تحديثات البيانات، تحقق من أن الجهاز يمكنه توفير نوع البيانات التي يحتاجها تطبيقك. يتيح لك التحقق من الإمكانات تفعيل ميزات معيّنة أو إيقافها أو تعديل واجهة المستخدم في تطبيقك لتعويض الميزات غير المتوفّرة.

val healthClient = HealthServices.getClient(this /*context*/)
val passiveMonitoringClient = healthClient.passiveMonitoringClient
lifecycleScope.launchWhenCreated {
    val capabilities = passiveMonitoringClient.capabilities.await()
    // Supported types for passive data collection
    supportsHeartRate =
        DataType.HEART_RATE_BPM in capabilities.supportedDataTypesPassiveMonitoring
    // Supported types for PassiveGoals
    supportsStepsGoal =
        DataType.STEPS_DAILY in capabilities.supportedDataTypesPassiveGoals
}

التسجيل للبيانات السلبية

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

مهما كانت الطريقة التي تستخدمها، أنشئ أولاً PassiveListenerConfig تحدد أنواع البيانات التي سيتم تلقّيها، كما هو موضّح في المثال التالي:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDataTypes(setOf(DataType.HEART_RATE_BPM))
    .build()

لتلقّي البيانات باستخدام معاودة الاتصال، يُرجى تحديد معاودة الاتصال وتسجيلها، كما هو موضّح في المثال التالي:

val passiveListenerCallback: PassiveListenerCallback = object : PassiveListenerCallback {
    override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
        // TODO: Do something with dataPoints
    }
}

passiveMonitoringClient.setPassiveListenerCallback(
    passiveListenerConfig,
    passiveListenerCallback
)

// To remove the listener
passiveMonitoringClient.clearPassiveListenerCallbackAsync()

يتشابه استخدام إحدى الخدمات، ولكن بدلاً من إنشاء فئة مشتقة من PassiveListenerCallback، يمكن اشتقاقها من PassiveListenerService، كما هو موضّح في المثال التالي:

class PassiveDataService : PassiveListenerService() {
    override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
        // TODO: Do something with dataPoints
    }
}

passiveMonitoringClient.setPassiveListenerServiceAsync(
    PassiveDataService::class.java,
    passiveListenerConfig
)

بعد ذلك، عليك الإفصاح عن الخدمة في ملف AndroidManifest.xml. طلب إذن "الخدمات الصحية" لضمان قدرة "الخدمات الصحية" فقط على الربط بالخدمة:

<service android:name=".PassiveDataService"
    android:permission="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"
    android:exported="true" />

تفسير الوقت

يتم تجميع البيانات التي تتلقاها من الخدمات الصحية بشكل مجمّع، لذلك قد تتلقى نقاط بيانات من أنواع مختلفة أو نقاط بيانات متعددة من النوع نفسه في الدفعة نفسها. ولتحديد الترتيب الصحيح للأحداث، استخدِم الطوابع الزمنية المضمّنة في هذه العناصر بدلاً من وقت تلقّيها لتطبيقك.

احصل على طوابع زمنية لكل DataPoint من خلال احتساب الطابع الزمني للتشغيل أولاً، كما هو موضّح في المثال التالي:

val bootInstant =
    Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())

يمكن بعد ذلك تمرير هذه القيمة إلى getStartInstant() أو getEndInstant().

استعادة عمليات التسجيل بعد التشغيل

لا تستمر عمليات تسجيل البيانات السلبية في جميع عمليات إعادة التشغيل. لتلقّي البيانات بعد إعادة تشغيل الجهاز، عليك إعادة إنشاء عمليات التسجيل باستخدام عنصر BroadcastReceiver يستمع إلى بث نظام ACTION_BOOT_COMPLETED.

في المُستلِم، لا تحاول استعادة التسجيلات مباشرةً. يمكنك بدلاً من ذلك تفويض هذه الوظيفة لعامل WorkManager. عند بدء تشغيل الجهاز، قد تستغرق الخدمات الصحية مدة 10 ثوانٍ أو أكثر للإقرار بطلب تسجيل بيانات سلبي، ما قد يتجاوز وقت تنفيذ BroadcastReceiver المسموح به. في المقابل، يُفرض على العاملين في WorkManager حد للتنفيذ يبلغ 10 دقائق.

يعرض المقتطف التالي الشكل الذي قد يبدو عليه BroadcastReceiver:

class StartupReceiver : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       if (intent.action != Intent.ACTION_BOOT_COMPLETED) return


       // TODO: Check permissions first
       WorkManager.getInstance(context).enqueue(
           OneTimeWorkRequestBuilder<RegisterForPassiveDataWorker>().build()
       )
   }
}

class RegisterForPassiveDataWorker(
   private val appContext: Context,
   workerParams: WorkerParameters
) : Worker(appContext, workerParams) {

   override fun doWork(): Result {
       runBlocking {
           HealthServices.getClient(appContext)
                .passiveMonitoringClient
                .setPassiveListenerCallback(...)
       }
       return Result.success()
   }
}

لترتيب تنفيذ هذا الرمز في النظام عند تشغيل الجهاز، عليك إجراء تغييرين في ملف AndroidManifest.xml.

أولاً، عليك إضافة الإذن التالي باعتباره عنصرًا فرعيًا لـ <manifest>:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

ثانيًا، أضِف فلتر أهداف المُستلِم التالي كعنصر ثانوي للسمة <application>:

<receiver
    android:name=".StartupReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

حالة النشاط

يمكن للعميل السلبي أيضًا توفير معلومات عالية المستوى عن حالة المستخدم، مثل ما إذا كان المستخدم نائمًا. وللحصول على هذه التحديثات، اتبع الخطوات التالية:

  1. يُرجى طلب الحصول على إذن "ACTIVITY_RECOGNITION".
  2. يمكنك طلب الرقم setShouldUserActivityInfoBeRequested(true) في أداة إنشاء PassiveListenerConfig.

يمكنك إلغاء طريقة onUserActivityInfoReceived() في معاودة الاتصال أو الخدمة والاستفادة من UserActivityInfo المعروضة، كما هو موضَّح في المثال التالي:

override fun onUserActivityInfoReceived(info: UserActivityInfo) {
    val stateChangeTime: Instant = info.stateChangeTime // may be in the past!
    val userActivityState: UserActivityState = info.userActivityState
    if (userActivityState == UserActivityState.USER_ACTIVITY_ASLEEP) {
        // ...
    }
}

الأهداف السلبية

يمكنك تهيئة عميل سلبي لإشعار التطبيق عند الوصول إلى الأهداف السلبية، مثل إكمال المستخدم 10000 خطوة في اليوم.

للقيام بذلك، أنشئ هدفًا كما هو موضح في المثال التالي:

val dailyStepsGoal by lazy {
    val condition = DataTypeCondition(
        dataType = DataType.STEPS_DAILY,
        threshold = 10_000, // Trigger every 10000 steps
        comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
    )
    PassiveGoal(condition)
}

أضِف هذا الهدف إلى PassiveListenerConfig، كما هو موضّح في المثال التالي:

val passiveListenerConfig = PassiveListenerConfig.builder()
    .setDailyGoals(setOf(dailyStepsGoal))
    .build()

يمكنك إلغاء طريقة onGoalCompleted() في معاودة الاتصال أو الخدمة والاستفادة من PassiveGoal المعروضة، كما هو موضَّح في المثال التالي:

override fun onGoalCompleted(goal: PassiveGoal) {
    when (goal.dataTypeCondition.dataType) {
        DataType.STEPS_DAILY -> {
            // ...
        }
    }
}