قيود النظام على العمل في الخلفية

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

لتجنب قيود النظام، تأكد من استخدام واجهة برمجة التطبيقات المناسبة لمهمة الخلفية. تساعدك مستندات نظرة عامة على المهام التي يتم تنفيذها في الخلفية في اختيار واجهة برمجة التطبيقات المناسبة لاحتياجاتك.

القيود التي يبدأها المستخدم

إذا كان أحد التطبيقات يعرض بعض السلوكيات السيئة الموضّحة في مؤشرات Android الحيوية، يطلب النظام من المستخدم تقييد وصول هذا التطبيق إلى موارد النظام.

فإذا لاحظ النظام أن أحد التطبيقات يستنفد موارد زائدة، فسيبلغ المستخدم، ويوفر للمستخدم خيار تقييد إجراءات التطبيق. تشمل السلوكيات التي تؤدي إلى إرسال الإشعار ما يلي:

  1. عمليات قفل التنشيط المفرطة: يتم تثبيت قفل تنشيط جزئي واحد لمدة ساعة عندما تكون الشاشة مطفأة.
  2. الخدمات المفرطة في الخلفية: إذا كان التطبيق يستهدف مستويات أقل من 26 لواجهة برمجة التطبيقات ويحتوي على خدمات خلفية زائدة

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

القيود المفروضة على تلقّي عمليات بث أنشطة الشبكة

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

جدولة العمل عبر الاتصالات التي لا تفرض تكلفة استخدام

عند إنشاء WorkRequest، أضِف NetworkType.UNMETERED Constraint.

fun scheduleWork(context: Context) {
    val workManager = WorkManager.getInstance(context)
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
       .setConstraints(
           Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .build()
           )
       .build()

    workManager.enqueue(workRequest)
}

عند استيفاء شروط عملك، يتلقّى تطبيقك استدعاءًا لتشغيل طريقة doWork() في فئة Worker المحدّدة.

مراقبة الاتصال بالشبكة أثناء تشغيل التطبيق

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

تحدد كائنات NetworkRequest معلمات معاودة الاتصال بالشبكة من حيث NetworkCapabilities. يمكنك إنشاء كائنات NetworkRequest باستخدام الفئة NetworkRequest.Builder. registerNetworkCallback ثم يمرِّر الكائن NetworkRequest إلى النظام. عند استيفاء شروط الشبكة، يتلقى التطبيق استدعاءًا لتنفيذ طريقة onAvailable() المحدّدة في فئته ConnectivityManager.NetworkCallback.

يستمر التطبيق في تلقّي معاودة الاتصال حتى يتم الخروج من التطبيق أو عند استدعاء unregisterNetworkCallback().

القيود المفروضة على تلقي عمليات بث الصور والفيديوهات

لا يمكن للتطبيقات إرسال أو تلقّي عمليات بث ACTION_NEW_PICTURE أو ACTION_NEW_VIDEO. وتساعد هذه القيود في الحدّ من تأثيرات الأداء وتجربة المستخدم في الحالات التي يجب فيها تنشيط العديد من التطبيقات لمعالجة صورة أو فيديو جديدَين.

تحديد جهات المحتوى التي بدأت العمل

يسمح WorkerParameters لتطبيقك بتلقّي معلومات مفيدة حول مصادر المحتوى ومعرّفات الموارد المنتظمة (URI) التي أدّت إلى العمل:

List<Uri> getTriggeredContentUris()

تعرض قائمة بمعرّفات الموارد المنتظمة (URI) التي أدّت إلى العمل. يكون هذا الحقل فارغًا إذا لم يتم بدء العمل من خلال معرّفات الموارد المنتظمة (URI) (على سبيل المثال، إذا تم بدء العمل بسبب موعد نهائي أو لسبب آخر)، أو إذا كان عدد معرّفات الموارد المنتظمة التي تم تغييرها أكبر من 50.

List<String> getTriggeredContentAuthorities()

تعرض قائمة سلاسل تضم مراجع المحتوى التي بدأت العمل. إذا لم تكن القائمة التي تم عرضها فارغة، استخدِم getTriggeredContentUris() لاسترداد تفاصيل معرّفات الموارد المنتظمة التي تم تغييرها.

يلغي نموذج الرمز التالي طريقة CoroutineWorker.doWork() ويسجّل جهات المحتوى ومعرّفات الموارد المنتظمة (URI) التي أدّت إلى تنفيذ المهمة:

class MyWorker(
    appContext: Context,
    params: WorkerParameters
): CoroutineWorker(appContext, params)
    override suspend fun doWork(): Result {
        StringBuilder().apply {
            append("Media content has changed:\n")
            params.triggeredContentAuthorities
                .takeIf { it.isNotEmpty() }
                ?.let { authorities ->
                    append("Authorities: ${authorities.joinToString(", ")}\n")
                    append(params.triggeredContentUris.joinToString("\n"))
                } ?: append("(No content)")
            Log.i(TAG, toString())
        }
        return Result.success()
    }
}

اختبار التطبيق في ظل قيود النظام

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

يمكن أن تساعدك بعض أوامر Android Debug Bridge (ADB) الإضافية في اختبار سلوك التطبيق مع إيقاف العمليات في الخلفية:

  • لمحاكاة الظروف التي تكون فيها عمليات البث الضمني والخدمات في الخلفية غير متوفرة، أدخِل الأمر التالي:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore

  • لإعادة تفعيل عمليات البث الضمني والخدمات في الخلفية، أدخِل الأمر التالي:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow

تحسين تطبيقك أكثر

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