عندما يتم حظر سلسلة واجهة المستخدم لتطبيق 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، يمكنك اتّباع الإرشادات الواردة في هذا المستند لتشخيص المشكلة وحلّها.
الكشف عن المشكلة
إذا سبق لك نشر تطبيقك، يمكنك استخدام "مؤشرات Android الحيوية" للاطّلاع على معلومات حول أخطاء ANR في تطبيقك. ويمكنك استخدام أدوات أخرى لرصد أخطاء ANR في بيئة التشغيل، ولكن يُرجى العِلم بأنّ أدوات الجهات الخارجية لا يمكنها رصد أخطاء ANR على الإصدار 10 من نظام التشغيل Android والإصدارات الأقدم، على عكس "مؤشرات Android الحيوية".
مؤشرات Android الحيوية
يمكن أن تساعدك "مؤشرات Android الحيوية" في مراقبة نسبة أخطاء ANR وتحسينها في تطبيقك. تقيس "مؤشرات Android الحيوية" عدة نسب لأخطاء ANR، وهي:
- نسبة أخطاء ANR: هي النسبة المئوية للمستخدمين النشطين يوميًا الذين واجهوا أي نوع من أخطاء ANR.
- نسبة أخطاء ANR التي لاحظها المستخدمون: هي النسبة المئوية للمستخدمين النشطين يوميًا الذين واجهوا خطأ ANR واحدًا على الأقل من الأخطاء التي لاحظها المستخدمون. في الوقت الحالي، يتم احتساب أخطاء ANR من النوع
Input dispatching timed outفقط ضمن أخطاء ANR التي لاحظها المستخدم. - نسبة أخطاء ANR المتعددة: هي النسبة المئوية للمستخدمين النشطين يوميًا الذين واجهوا خطأين على الأقل من نوع ANR.
المستخدم النشط يوميًا هو مستخدم فريد يستخدم تطبيقك في يوم واحد على جهاز واحد، وقد يكون ذلك خلال جلسات متعدّدة. فإذا كان أحد المستخدمين يستخدم تطبيقك على أكثر من جهاز في يوم واحد، سيساهم كل جهاز في عدد المستخدمين النشطين لذلك اليوم.
إنّ نسبة أخطاء ANR التي لاحظها المستخدمون هي أحد مؤشرات الأداء الأساسية، أي أنّها تؤثر في قابلية اكتشاف تطبيقك على Google Play. وهذا مهم لأنّ أخطاء ANR التي يتم احتسابها تحدث دائمًا عندما يتفاعل المستخدم مع التطبيق، ما يؤدي إلى حدوث أكبر خلل في الأداء.
حدّد Play معيارَين لتحديد الأداء السيئ لهذا المقياس:
- معيار تحديد الأداء السيئ العام: يواجه ما لا يقل عن% 0.47 من المستخدمين النشطين يوميًا خطأ ANR لاحظه المستخدم، في جميع طُرز الأجهزة.
- معيار تحديد الأداء السيئ حسب الجهاز: يواجه% 8 على الأقل من المستخدمين اليوميين خطأ ANR لاحظه المستخدم لطراز جهاز واحد.
إذا تجاوز تطبيقك معيار تحديد الأداء السيئ الإجمالي، من المرجَّح أن تنخفض فرص العثور عليه على جميع الأجهزة. إذا تجاوز تطبيقك معيار تحديد الأداء السيئ لكل جهاز على بعض الأجهزة، من المرجَّح أن تنخفض فرص العثور عليه على هذه الأجهزة، وقد يظهر تحذير في بطاقة بيانات المتجر.
يمكن أن تنبّهك "مؤشرات Android الحيوية" من خلال Play Console عندما يعرض تطبيقك عددًا كبيرًا من أخطاء ANR.
للحصول على معلومات حول كيفية جمع Google Play لبيانات "مؤشرات Android الحيوية"، يُرجى الاطّلاع على مستندات Play Console.
تشخيص أخطاء ANR
هناك بعض الأنماط الشائعة التي يجب البحث عنها عند تشخيص أخطاء ANR:
- يُجري التطبيق عمليات بطيئة تتضمّن وحدات الإدخال والإخراج في سلسلة التعليمات الرئيسية.
- يُجري التطبيق عملية حسابية طويلة في سلسلة المحادثات الرئيسية.
- تُجري سلسلة التعليمات الرئيسية طلبًا متزامنًا من الصنف 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 غير مفعّلة
- عمليات تنبيه مفرطة