عندما يتم حظر سلسلة واجهة المستخدم لتطبيق Android لفترة طويلة جدًا، يتم تشغيل خطأ "التطبيق لا يستجيب" (ANR). إذا كان التطبيق يعمل في المقدّمة، يعرض النظام مربّع حوار للمستخدم، كما هو موضّح في الشكل 1. يمنح مربّع حوار ANR المستخدم فرصة لإغلاق التطبيق بالقوة.
تُعدّ أخطاء ANR مشكلة لأنّ سلسلة التعليمات البرمجية الرئيسية للتطبيق، المسؤولة عن تعديل واجهة المستخدم، لا يمكنها معالجة أحداث بيانات أدخلها المستخدم أو عرضها، ما يؤدي إلى إحباط المستخدم. لمزيد من المعلومات حول سلسلة التعليمات الرئيسية للتطبيق، اطّلِع على نظرة عامة على العمليات وسلاسل التعليمات.
يتم بدء خطأ ANR في تطبيقك عند حدوث أحد الشروط التالية:
- انتهت المهلة المحدّدة لإرسال الإدخال: يحدث ذلك إذا لم يستجب تطبيقك لحدث إدخال (مثل الضغط على مفتاح أو لمس الشاشة) في غضون 5 ثوانٍ.
- تنفيذ الخدمة: إذا لم تتمكّن خدمة تم الإعلان عنها في تطبيقك من إكمال تنفيذ
Service.onCreateوService.onStartCommand/Service.onBindفي غضون بضع ثوانٍ. - لم يتم استدعاء
Service.startForeground: إذا كان تطبيقك يستخدمContext.startForegroundServiceلبدء خدمة جديدة تعمل في المقدّمة، ولكن لم تستدعِ الخدمةstartForegroundفي غضون 5 ثوانٍ. - بث النية: إذا لم تنتهِ
BroadcastReceiverمن التنفيذ خلال فترة زمنية محدّدة. إذا كان التطبيق نشطًا في المقدّمة، تكون مدة المهلة 5 ثوانٍ. - تفاعلات
JobScheduler: إذا لم يتم عرضJobServiceمنJobService.onStartJobأوJobService.onStopJobفي غضون بضع ثوانٍ، أو إذا بدأت مهمة بدأها المستخدم ولم يستدعِ تطبيقكJobService.setNotificationفي غضون بضع ثوانٍ بعد استدعاءJobService.onStartJob. بالنسبة إلى التطبيقات التي تستهدف الإصدار 13 من نظام التشغيل Android والإصدارات الأقدم، تكون أخطاء ANR غير ظاهرة ولا يتم إبلاغ التطبيق بها. أما بالنسبة إلى التطبيقات التي تستهدف الإصدار 14 من نظام التشغيل Android والإصدارات الأحدث، فتكون أخطاء ANR ظاهرة ويتم إبلاغ التطبيق بها.
إذا كان تطبيقك يعاني من أخطاء ANR، يمكنك اتّباع الإرشادات الواردة في هذا المستند لتشخيص المشكلة وحلّها.
تشخيص أخطاء ANR
هناك بعض الأنماط الشائعة التي يجب البحث عنها عند تشخيص أخطاء ANR:
- يُجري التطبيق عمليات بطيئة تتضمّن وحدات الإدخال والإخراج في سلسلة التعليمات الرئيسية.
- يُجري التطبيق عملية حسابية طويلة في سلسلة المحادثات الرئيسية.
- تُجري سلسلة التعليمات الرئيسية طلبًا متزامنًا من الصنف Binder إلى عملية أخرى، وتستغرق هذه العملية الأخرى وقتًا طويلاً للعودة.
- تم حظر سلسلة التعليمات الرئيسية في انتظار كتلة متزامنة لعملية طويلة الأمد تحدث في سلسلة تعليمات أخرى.
- تكون سلسلة التعليمات الرئيسية في حالة توقّف تام مع سلسلة تعليمات أخرى، إما في عمليتك أو من خلال طلب binder. لا تنتظر سلسلة التعليمات الرئيسية انتهاء عملية طويلة فقط، بل هي في حالة توقف تام.
يمكن أن تساعدك التقنيات التالية في تحديد سبب أخطاء ANR.
HealthStats
توفّر HealthStats مقاييس حول سلامة التطبيق من خلال تسجيل إجمالي وقت المستخدم ووقت النظام ووقت وحدة المعالجة المركزية والشبكة وإحصاءات الراديو ووقت تشغيل/إيقاف الشاشة وتنبيهات التنشيط. ويمكن أن يساعدك ذلك في قياس الاستخدام الإجمالي لوحدة المعالجة المركزية (CPU) ومعدّل استنزاف البطارية.
تصحيح الأخطاء
تساعدك أداة Debug في فحص تطبيقات Android أثناء عملية التطوير، بما في ذلك تتبُّع عدد مرات التخصيص وعمليات التتبُّع لتحديد المشاكل في التطبيقات، مثل إيقاف مؤقت لعرض واجهة المستخدم والتأخير.
يمكنك أيضًا استخدام Debug للحصول على عدّادات وقت التشغيل والذاكرة الأصلية، ومقاييس الذاكرة التي يمكن أن تساعدك في تحديد استهلاك الذاكرة لعملية معيّنة.
ApplicationExitInfo
تتوفّر ApplicationExitInfo على الإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، وتقدّم معلومات عن سبب خروج التطبيق. ويشمل ذلك أخطاء ANR ونقص الذاكرة وتعطُّل التطبيق والاستخدام المفرط لوحدة المعالجة المركزية ومقاطعات المستخدم ومقاطعات النظام والتغييرات في أذونات وقت التشغيل.
الوضع المقيَّد
يساعدك استخدام StrictMode في العثور على عمليات إدخال/إخراج غير مقصودة في سلسلة التعليمات الرئيسية أثناء تطوير تطبيقك. ويمكنك استخدام StrictMode على مستوى التطبيق أو النشاط.
تفعيل مربّعات حوار أخطاء ANR في الخلفية
لا يعرض نظام التشغيل Android مربّعات حوار ANR للتطبيقات التي تستغرق وقتًا طويلاً في معالجة رسالة البث إلا إذا تم تفعيل الخيار عرض جميع أخطاء ANR في خيارات المطوّرين على الجهاز. لهذا السبب، لا يتم دائمًا عرض مربّعات حوار ANR في الخلفية للمستخدم، حتى عندما يواجه التطبيق مشاكل في الأداء.
المشاكل التي تعيق إعادة التكوين
استخدِم أداة Profiler في "استوديو Android" وأداة فحص التنسيق لتتبُّع المشاكل التي تؤدي إلى بطء إعادة الإنشاء. لمزيد من المعلومات، يُرجى الاطّلاع على أداء Jetpack Compose.
سحب ملفات التتبُّع
تخزِّن متاجر Android معلومات التتبُّع عند حدوث خطأ ANR. في إصدارات نظام التشغيل القديمة، يتوفّر ملف /data/anr/traces.txt واحد على الجهاز. في إصدارات نظام التشغيل الأحدث، تتوفّر ملفات /data/anr/anr_* متعددة. يمكنك الوصول إلى عمليات تتبُّع أخطاء ANR
من جهاز أو محاكي باستخدام Android Debug Bridge (adb) كجذر باتّباع الخطوات التالية:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
يمكنك تسجيل تقرير بالأخطاء من جهاز فعلي باستخدام خيار المطوّرين "إعداد تقرير بالأخطاء" على الجهاز أو باستخدام الأمر adb bugreport على جهاز التطوير. لمزيد من المعلومات، يُرجى الاطّلاع على تسجيل تقارير الأخطاء وقراءتها.
حلّ المشاكل
بعد تحديد المشكلة، يمكنك استخدام النصائح الواردة في هذا القسم لحل المشاكل الشائعة.
رمز بطيء في سلسلة التعليمات الرئيسية
حدِّد المواضع في الرمز البرمجي التي تكون فيها سلسلة التعليمات الرئيسية للتطبيق مشغولة لمدة تزيد عن 5 ثوانٍ. ابحث عن حالات الاستخدام المشبوهة في تطبيقك وحاوِل إعادة إنتاج خطأ ANR.
من المشاكل الشائعة تنفيذ مهمة تستغرق وقتًا طويلاً مباشرةً في عنصر قابل للإنشاء:
@Composable
fun BadList(rawStrings: List<String>) {
// Math or sorting inside the composable runs on EVERY recomposition pass!
val heavilyProcessedList = rawStrings
.filter { it.isNotBlank() }
.map { it.uppercase().reversed() }
.map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
LazyColumn { items(sortedList) { Text(it) } }
}
// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// UI simply renders state; no heavy processing allowed here
LazyColumn { items(uiState.sortedData) { Text(it) } }
}
عمليات الإدخال والإخراج في سلسلة التعليمات الرئيسية
يُعدّ تنفيذ عمليات الإدخال والإخراج في سلسلة التعليمات الرئيسية سببًا شائعًا لبطء العمليات في سلسلة التعليمات الرئيسية، ما قد يؤدي إلى حدوث أخطاء ANR. في Compose، غالبًا ما يؤدي المطوّرون عن غير قصد إلى تشغيل عمليات قراءة من القرص (مثل SharedPreferences أو طلبات قاعدة البيانات) أثناء محاولة استخلاص الحالة الأولية.
تنفيذ عمليات الإدخال/الإخراج التي تستغرق وقتًا طويلاً بعيدًا عن طبقة واجهة المستخدم استخدِم
withContext(Dispatchers.IO) في ViewModel أو استخدِم Repository في طبقة البيانات.
حالات التوقف التام
يحدث التوقف التام عندما تدخل سلسلة تعليمات في حالة انتظار لأنّ سلسلة تعليمات أخرى تحتفظ بمورد مطلوب، وتنتظر هذه السلسلة أيضًا موردًا تحتفظ به سلسلة التعليمات الأولى. إذا كانت سلسلة التعليمات الرئيسية للتطبيق في هذا الموقف، من المحتمل حدوث أخطاء ANR.
حالات التعطّل التام هي ظاهرة معروفة في علوم الكمبيوتر، وهناك خوارزميات لمنع حدوثها يمكنك استخدامها لتجنُّبها.
لمزيد من المعلومات، يمكنك الاطّلاع على مقالتَي التوقف التام وخوارزميات منع التوقف التام على ويكيبيديا.
عند استخدام Kotlin وCompose، يمكنك استبدال عمليات القفل الأساسية بعمليات قفل Mutex غير حاصرة في الروتينات المشتركة (Mutex.withLock) لمنع حظر سلسلة التعليمات من خلال تعليق سياق التنفيذ بدلاً من تجميد سلسلة تعليمات واجهة المستخدم. على سبيل المثال:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
// Modern non-blocking concurrency state architecture
class SecureDataRepository {
private val mutex = Mutex()
suspend fun safeUIAccess() {
// If locked, the main thread suspends seamlessly, preventing an ANR
mutex.withLock {
performSafeOperation()
}
}
}
مستقبِلات البث البطيئة
يمكن للتطبيقات الرد على الرسائل المتعددة البث، مثل تفعيل وضع الطيران أو إيقافه أو تغيير حالة الاتصال، وذلك باستخدام أدوات استقبال البث. يحدث خطأ ANR عندما يستغرق التطبيق وقتًا طويلاً جدًا لمعالجة الإعلان على جميع الأجهزة.
يحدث خطأ ANR في الحالات التالية:
- لم ينتهِ جهاز استقبال البث من تنفيذ طريقة
onReceiveخلال فترة زمنية كبيرة. - يطلب جهاز استقبال البث
goAsyncويتعذّر عليه طلبfinishمن الكائنPendingResult.
يجب أن ينفّذ تطبيقك عمليات قصيرة فقط في طريقة onReceive ضمن BroadcastReceiver. ومع ذلك، إذا كان تطبيقك يتطلّب معالجة أكثر تعقيدًا نتيجةً لرسالة الإعلان على جميع الأجهزة، عليك تأجيل المهمة إلى ViewModel (الاستفادة من إمكانات إجراءات Kotlin الفرعية ونطاقاتها وموزّعاتها) إذا كان من المتوقّع أن تستغرق المهمة بضع ثوانٍ على الأكثر، أو إلى أي نوع من عناصر الاحتفاظ بالحالة، أو إلى WorkManager للمهام التي يُتوقّع أن تستغرق أكثر من بضع ثوانٍ.
GameActivity
قلّلت مكتبة GameActivity من أخطاء ANR في دراسات الحالة للألعاب والتطبيقات المكتوبة بلغة C أو C++. وإذا استبدلت نشاطك الحالي الأصلي بنشاط GameActivity، يمكنك تقليل حظر سلسلة التعليمات الخاصة بواجهة المستخدم ومنع حدوث بعض أخطاء ANR.
لمزيد من المعلومات عن أخطاء ANR، يُرجى الاطّلاع على مقالة الحفاظ على استجابة تطبيقك. لمزيد من المعلومات حول سلاسل المحادثات، يُرجى الاطّلاع على تحسين الأداء من خلال سلاسل المحادثات.
مراجع إضافية
عرض المحتوى
مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- عمليات تنبيه مفرطة