تحسين الخلفية

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

للحدّ من هذه المشكلة، يطبّق الإصدار Android 7.0 (المستوى 24 لواجهة برمجة التطبيقات) ما يلي: القيود:

  • لن يتم تلقّي التطبيقات التي تستهدف الإصدار 7.0 من نظام التشغيل Android (المستوى 24 لواجهة برمجة التطبيقات) والإصدارات الأحدث CONNECTIVITY_ACTION عمليات بث إذا كانت الإشارة إلى مستقبِل البث في البيان. وستظل التطبيقات تلقّي CONNECTIVITY_ACTION إعلان على جميع الأجهزة في حال التسجيل BroadcastReceiver مع Context.registerReceiver() وهذا السياق لا يزال صالحًا.
  • لا يمكن للتطبيقات إرسال أو استقبال رسائل بث ACTION_NEW_PICTURE أو ACTION_NEW_VIDEO. هذا التحسين في كل التطبيقات، وليس فقط في التطبيقات التي تستهدف الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات).

إذا كان تطبيقك يستخدم أيًا من هذه الأغراض، يجب إزالة التبعيات عليها. في أقرب وقت ممكن، حتى تتمكّن من استهداف الأجهزة التي تعمل بنظام التشغيل Android 7.0 بشكل صحيح. أو أعلى. يوفر إطار عمل Android العديد من الحلول لتخفيف الحاجة إليها لعمليات البث الضمنية. على سبيل المثال، JobScheduler و يوفر WorkManager الجديد آليات قوية لجدولة مواعيد الشبكة العمليات عندما تكون هناك شروط محددة، مثل الاتصال بوحدة قياس شبكة الإنترنت. يمكنك الآن أيضًا استخدام "JobScheduler" للاستجابة للتغييرات التي تطرأ على موفّري المحتوى. JobInfo تضم الكائنات المعاملين التي JobScheduler المستخدم لجدولة وظيفتك. عند استيفاء شروط الوظيفة، يطبق النظام ينفذ هذا الإجراء على JobService لتطبيقك.

وفي هذه الصفحة، سنتعرف على كيفية استخدام طرق بديلة، مثل JobScheduler، لتكييف تطبيقك مع هذه الميزات القيود.

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

في صفحة استخدام البطارية ضِمن النظام الإعدادات، يمكن للمستخدم يُرجى الاختيار من بين الخيارات التالية:

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

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

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

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

تحدِّد الشركة المصنّعة للجهاز القيود الدقيقة التي تفرضها. بالنسبة على سبيل المثال، في إصدارات AOSP التي تعمل بنظام التشغيل Android 9 (المستوى 28 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكن للتطبيقات يتم تشغيله في الخلفية التي تكون في الحالة "محظور" على ما يلي القيود:

  • لا يمكن تشغيل الخدمات التي تعمل في المقدّمة
  • تتم إزالة الخدمات الحالية التي تعمل في المقدّمة من المقدّمة.
  • المنبّهات غير مُفعَّلة.
  • لم يتم تنفيذ المهام

بالإضافة إلى ذلك، إذا كان التطبيق يستهدف الإصدار 13 من نظام التشغيل Android (المستوى 33) أو إصدارًا أحدث وكان ضمن "محظور" النظام لا يرسل بث BOOT_COMPLETED أو بث LOCKED_BOOT_COMPLETED إلى أن يتم تشغيل التطبيق على أجهزة أخرى الأسباب.

يتم سرد القيود المحددة في قيود إدارة الطاقة:

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

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

ملاحظة: يتم تسجيل BroadcastReceiver في Context.registerReceiver() مواصلة تلقّي عمليات البث هذه أثناء تشغيل التطبيق.

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

عند استخدام الصف JobInfo.Builder لإنشاء كائن JobInfo، طبِّق الطريقة setRequiredNetworkType() ومرِّر JobInfo.NETWORK_TYPE_UNMETERED كمَعلمة مهمة. نموذج التعليمة البرمجية التالي جدولة خدمة لتشغيلها عند اتصال الجهاز بخدمة لا تفرض تكلفة استخدام الشبكة ويجري الشحن:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MyJobService::class.java)
    )
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
            .setRequiresCharging(true)
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo job = new JobInfo.Builder(
    MY_BACKGROUND_JOB,
    new ComponentName(context, MyJobService.class))
      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
      .setRequiresCharging(true)
      .build();
  js.schedule(job);
}

عند استيفاء شروط وظيفتك، يتلقّى تطبيقك معاودة الاتصال لتشغيله. طريقة onStartJob() في تم تحديد JobService.class. للاطّلاع على المزيد من الأمثلة على تنفيذ JobScheduler، يُرجى الاطّلاع على نموذج تطبيق Job Scheduler.

ويشكّل WorkManager بديلاً جديدًا لـ Job Scheduler، وهو واجهة برمجة تطبيقات تتيح لك جدولة للمهام الخلفية التي تحتاج إكمال الدورة التدريبية بنجاح، بغض النظر عمّا إذا كانت عملية التطبيق متاحة أم لا مدير العمل اختيار الطريقة المناسبة لتشغيل العمل (إما مباشرةً عبر سلسلة محادثات في عملية التطبيق بالإضافة إلى استخدام Job Scheduler أو FirebaseJobDispatcher أو AlarmManager) استنادًا إلى عوامل مثل مستوى واجهة برمجة التطبيقات للجهاز. بالإضافة إلى ذلك، لا يتطلب WorkManager خدمات Play ويوفر العديد من الميزات المتقدمة، مثل تسلسل المهام معًا أو التحقق من حالة المهمة. للتعلّم المزيد، يُرجى الاطِّلاع على WorkManager.

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

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

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

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

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

في الإصدار 7.0 من نظام التشغيل Android (المستوى 24 لواجهة برمجة التطبيقات)، لا يمكن للتطبيقات إرسال إعلانات بث باستخدام ACTION_NEW_PICTURE أو ACTION_NEW_VIDEO أو تلقّيها. يساعد هذا القيد بالحدّ من تأثيرات تجربة المستخدم والأداء عند الحاجة إلى تستيقظ لمعالجة صورة أو فيديو جديد. Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) وتوسِّع JobInfo وJobParameters لتوفير حل بديل.

تشغيل المهام عند تغيير معرّف الموارد المنتظم (URI) للمحتوى

لتشغيل المهام عند تغيير معرّف الموارد المنتظم (URI) للمحتوى، يتم توسيع Android 7.0 (مستوى واجهة برمجة التطبيقات 24) JobInfo API بالطرق التالية:

JobInfo.TriggerContentUri()
يتضمّن هذا الحقل المَعلمات المطلوبة لتشغيل مهمة بخصوص تغييرات معرّفات الموارد المنتظمة (URI) للمحتوى.
JobInfo.Builder.addTriggerContentUri()
تمرير كائن TriggerContentUri إلى JobInfo. ContentObserver عنوان URI للمحتوى المتضمن. وإذا كان هناك عدة عناصر TriggerContentUri مرتبطة بمهمة معيّنة، سيوفّر النظام حتى في حال تسجيل تغيير في معرّف موارد منتظم (URI) واحد فقط للمحتوى.
إضافة علامة TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS إلى يؤدي هذا الإجراء إلى تشغيل المهمة في حال تغيير أي عناصر تابعة لعنوان URI المحدد. هذه العلامة مع معلمة notifyForDescendants التي تم تمريرها إلى registerContentObserver().

ملاحظة: لا يمكن استخدام TriggerContentUri() في مع setPeriodic() أو setPersisted(). لمراقبة تغييرات المحتوى باستمرار، يمكنك جدولة JobInfo قبل أن ينتهي JobService للتطبيق من معالجة آخر معاودة الاتصال.

يحدّد الرمز النموذجي التالي مهمة لبدء تشغيلها عندما يبلغ النظام تغيير في معرف الموارد المنتظم (URI) للمحتوى، MEDIA_URI:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MediaContentJob::class.java)
    )
            .addTriggerContentUri(
                    JobInfo.TriggerContentUri(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
                    )
            )
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo.Builder builder = new JobInfo.Builder(
          MY_BACKGROUND_JOB,
          new ComponentName(context, MediaContentJob.class));
  builder.addTriggerContentUri(
          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
  js.schedule(builder.build());
}

عندما يُبلغ النظام عن حدوث تغيير في معرِّفات الموارد المنتظمة(URI) للمحتوى المحدّدة، تطبيقك يتلقّى معاودة اتصال ويكون عنصر JobParameters تم إرسالها إلى onStartJob() في MediaContentJob.class.

تحديد مصادر المحتوى التي أدّت إلى أداء وظيفة

يمتد أيضًا الإصدار Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) من JobParameters إلى السماح لتطبيقك بتلقّي معلومات مفيدة عن مصادر المحتوى وشغّلت معرّفات الموارد المنتظمة (URI) الوظيفة:

Uri[] getTriggeredContentUris()
تعرض مصفوفة من معرفات الموارد المنتظمة (URI) التي أدت إلى تشغيل المهمة. ستكون هذه القيمة null إذا لم يتم تشغيل المهمة بعد أي معرّفات موارد منتظمة (URI) (على سبيل المثال، كانت الوظيفة بسبب موعد نهائي أو سبب آخر) أو تغير عدد معرفات الموارد المنتظمة (URI) أكبر من 50.
String[] getTriggeredContentAuthorities()
تعرض مصفوفة سلسلة من مراجع المحتوى التي شغَّلت المهمة. إذا لم يكن الصفيف المعروض هو null، استخدِم getTriggeredContentUris(). لعرض تفاصيل معرفات الموارد المنتظمة (URI) التي تم تغييرها.

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

Kotlin

override fun onStartJob(params: JobParameters): Boolean {
    StringBuilder().apply {
        append("Media content has changed:\n")
        params.triggeredContentAuthorities?.also { authorities ->
            append("Authorities: ${authorities.joinToString(", ")}\n")
            append(params.triggeredContentUris?.joinToString("\n"))
        } ?: append("(No content)")
        Log.i(TAG, toString())
    }
    return true
}

Java

@Override
public boolean onStartJob(JobParameters params) {
  StringBuilder sb = new StringBuilder();
  sb.append("Media content has changed:\n");
  if (params.getTriggeredContentAuthorities() != null) {
      sb.append("Authorities: ");
      boolean first = true;
      for (String auth :
          params.getTriggeredContentAuthorities()) {
          if (first) {
              first = false;
          } else {
             sb.append(", ");
          }
           sb.append(auth);
      }
      if (params.getTriggeredContentUris() != null) {
          for (Uri uri : params.getTriggeredContentUris()) {
              sb.append("\n");
              sb.append(uri);
          }
      }
  } else {
      sb.append("(No content)");
  }
  Log.i(TAG, sb.toString());
  return true;
}

زيادة تحسين تطبيقك

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

ما يلي 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
    
  • يمكنك محاكاة وضع المستخدم لتطبيقك في "وضع تقييد المحتوى". ولاية استخدام البطارية في الخلفية. يمنع هذا الإعداد تشغيل تطبيقك. في الخلفية. لإجراء ذلك، شغِّل الأمر التالي في نافذة طرفية:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny