ANR (Application Not Responding) هو إشعار نظام في أندرويد يظهر عندما لا يستجيب التطبيق للإدخال لمدة 5 ثوانٍ. على عكس الأخطاء المنطقية (أخطاء منطقية دون حظر واجهة المستخدم) والتباطؤ (بطء دون توقف كامل)، ANR هو عطل خطير يسجله نظام التشغيل: يعرض أندرويد حوار «التطبيق لا يستجيب» مع خيار الإغلاق أو الانتظار. وفقاً لـ Android Vitals Documentation، التطبيقات التي يزيد معدل ANR فيها عن 0.5% تحصل على تقييم أقل في Google Play وقد يتم إخفاؤها من التوصيات. يشمل التشخيص تحليل /data/anr/traces.txt، واستخدام StrictMode، وتوصيف السلسلة الرئيسية.
الخلاصة
ANR (Application Not Responding) هو آلية حماية للمستخدم في أندرويد يتم تفعيلها عندما يتوقف التطبيق عن الاستجابة للإدخال. يتتبع النظام وقت معالجة الأحداث: إذا لم يكمل BroadcastReceiver onReceive خلال 10 ثوانٍ، أو لم يعد Service من onCreate خلال 20 ثانية، أو لم يستجب ContentProvider خلال 15 ثانية — يقوم أندرويد بتوليد ANR.
عند حدوث ANR، يعرض أندرويد حوار نظام فوق جميع النوافذ: «التطبيق لا يستجيب. هل تريد إغلاقه أو الانتظار؟». يمكن للمستخدم إغلاق التطبيق أو انتظار استرداده. إذا تكرر ANR بشكل متكرر، يقوم المستخدم بإلغاء تثبيت التطبيق. يراعي Google Play معدل ANR — النسبة المئوية للجلسات مع ANR — في خوارزميات التصنيف الخاصة به.
لا يوجد في iOS ما يعادل ANR مع حوار النظام. بدلاً من ذلك، تستخدم Apple Watchdog الذي ينهي العملية برمز الخروج 0x8badf00d. لا يرى المستخدم حواراً — يتم إغلاق التطبيق ببساطة إلى الشاشة الرئيسية. هذا يجعل ANR على أندرويد أكثر وضوحاً للمستخدم ولكنه يعطي النظام مزيداً من معلومات التشخيص.
يحدث ANR عندما يتتبع النظام مهلة لأحد أربعة أنواع من المكونات. لكل مكون حد زمني خاص به.
BroadcastReceiver يتم تنفيذه في السلسلة الرئيسية. إذا بدأ onReceive طلب شبكة متزامن، أو كتابة طويلة في قاعدة البيانات، أو انتظر قفلاً — يحدث ANR خلال 10 ثوانٍ. الحل: استخدم goAsync() و WorkManager للمعالجة في الخلفية. السيناريو النموذجي هو استلام إشعار Push من FCM وحفظه بشكل متزامن في Room.
Service.onCreate و Service.onStartCommand لهما حد 20 ثانية. إذا بدأ الخدمة تهيئة ثقيلة (تحميل المكتبات، قراءة التهيئة من الشبكة) في السلسلة الرئيسية — ANR أمر لا مفر منه. استخدم IntentService (قديم) أو WorkManager للتنفيذ المضمون في الخلفية.
ContentProvider.onCreate يتم تنفيذه قبل Application.onCreate وله حد 15 ثانية. إذا قام المزود بترحيل قاعدة البيانات، أو تحميل القواميس، أو تهيئة SDK من الشبكة — فهذا يسبب ANR عند بدء تشغيل التطبيق. الحل: التهيئة البطيئة، تفريغ العمليات الثقيلة إلى WorkManager.
يوفر أندرويد عدة أدوات لتحليل ANR: من سجلات النظام إلى المكتبات المتخصصة.
عند كل ANR، يحفظ أندرويد الملف /data/anr/traces.txt مع تفريغ مكدس لجميع سلاسل التطبيق. ابحث عن السلسلة «main» — تشير آخر طريقة في المكدس إلى السبب. الأنماط النموذجية: Thread.sleep()، InputStream.read()، BinderProxy.transact(). لاستخراج الملف من الجهاز، استخدم adb بصلاحيات المستخدم المتميز.
Firebase Crashlytics يقوم تلقائياً بجمع ANR وعرضها في لوحة المعلومات مع التتبع. لأندرويد 11+، تأتي تقارير ANR مع مكدس كامل للسلسلة الرئيسية. يتطلب التكامل إضافة تبعية وتهيئة FirebaseApp في Application.onCreate.
CPU Profiler في Android Studio يتيح لك تسجيل تتبع التطبيق ورؤية أي الطرق تستهلك وقت المعالجة. فعّل «Record with method traces» وأعد إنتاج السيناريو الذي يسبب ANR. سيظهر الجدول الزمني أي الطرق كانت تعمل في السلسلة الرئيسية في وقت التجميد.
مثال على دمج Firebase Crashlytics لجمع ANR على أندرويد:
class App : Application() {
override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
FirebaseCrashlytics.getInstance()
.setCrashlyticsCollectionEnabled(true)
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
}
إصلاح ANR يعني بشكل أساسي نقل جميع العمليات الطويلة من السلسلة الرئيسية إلى سلاسل الخلفية. دعنا نلقي نظرة على تقنيات محددة لكل نوع من المكونات.
WorkManager هو الحل الموصى به من Google للعمل في الخلفية. يضمن تنفيذ المهمة في سلسلة خلفية مع مراعاة حالة الجهاز. على عكس Service، لا يحظر WorkManager السلسلة الرئيسية وهو مقاوم لإعادة تشغيل التطبيق. بالنسبة لـ BroadcastReceiver، استخدم goAsync() ومرر PendingResult إلى WorkManager.
قم بتشغيل جميع طلبات الشبكة وعمليات قاعدة البيانات وإدخال/إخراج الملفات باستخدام Dispatchers.IO. يجب أن تقوم السلسلة الرئيسية فقط بتحديث واجهة المستخدم. استخدم viewModelScope للإلغاء التلقائي للكوروتينات عند تدمير Activity. تجنب runBlocking() في أي سياق — فهو يحظر السلسلة الحالية بشكل متزامن.
إذا كان ContentProvider يقوم بتهيئة بطيئة، استخدم آلية التحميل البطيء: أنشئ مزوداً يعيد البيانات فوراً وابدأ التهيئة الثقيلة من خلال WorkManager مع تأخير. هذا يمنع ANR عند بدء تشغيل التطبيق، عندما يكون النظام أكثر حساسية للتأخيرات.
مثال على الاستخدام الصحيح لـ BroadcastReceiver مع goAsync في أندرويد:
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val pendingResult = goAsync()
WorkManager.getInstance(context!!)
.enqueue(OneTimeWorkRequest.from(NotificationWorker::class.java))
pendingResult.finish()
}
}
أفضل طريقة لمكافحة ANR هي منعها أثناء مرحلة التطوير من خلال الأدوات والقرارات المعمارية.
StrictMode مع السياسات المفعلة detectNetwork() و detectDiskReads()/detectDiskWrites() يحدد ANR المحتملة أثناء التطوير. في إصدارات Debug، قم بتعيين penaltyDeath — أي انتهاك سيؤدي إلى تعطل فوري وسيرى المطور المشكلة قبل الالتزام.
Firebase Performance يتتبع وقت تنفيذ العمليات الرئيسية ويظهر أي السيناريوهات تتجاوز عتبة ANR. قم بإعداد تتبعات مخصصة لكل شاشة وطلب شبكة. إذا تجاوز وقت التنفيذ 3 ثوانٍ — فهذا ANR محتمل يتطلب تحسيناً.
قم بمحاكاة الظروف البطيئة: حدد سرعة الشبكة باستخدام Network Link Conditioner على iOS أو Android Emulator. أبطئ قراءة القرص من خلال محاكاة الذاكرة البطيئة. ANR غالباً ما تظهر في هذه الظروف تحديداً، بينما تكون غير مرئية على أجهزة المطور السريعة.
الأسئلة الشائعة
أندرويد يتتبع وقت معالجة الأحداث بشكل صريح على السلسلة الرئيسية ويعرض حوار ANR. iOS يستخدم Watchdog الذي يغلق التطبيق قسراً عندما يتجمد لأكثر من 10–20 ثانية. ANR هي ميزة في معمارية أندرويد حيث تحتوي عدة مكونات (BroadcastReceiver، Service) على مهلات زمنية صارمة.
على أندرويد 11+ يمكنك الحصول على تفريغ ANR عبر adb shell dumpsys dropbox --print data_app_anr. على أندرويد 10 والإصدارات الأقدم، لا يمكن الوصول إلى /data/anr/traces.txt بدون صلاحيات الروت. استخدم Firebase Crashlytics — فهو يجمع تقارير ANR تلقائياً لأندرويد 11+.
يوصي Google Play بمعدل ANR أقل من 0.5% — أي لا يزيد عن 5 ANR لكل 1000 جلسة. التطبيق الذي يزيد معدله عن 1% يتلقى تحذيراً في Google Play Console وقد يتم إخفاؤه من التوصيات. من الناحية المثالية، يجب أن يكون معدل ANR أقل من 0.1%.
الكوروتين في حد ذاته لا يحظر السلسلة. ولكن إذا قمت بتنفيذ runBlocking داخل كوروتين على السلسلة الرئيسية أو تم تشغيل الكوروتين مع Dispatchers.Main وقامت بعملية CPU طويلة — فسيؤدي ذلك إلى ANR. استخدم Dispatchers.IO للإدخال/الإخراج و Dispatchers.Default للحسابات.
استخدم Android Emulator مع ملف تعريف «Slow Network» أو اكتب اختباراً يستدعي Thread.sleep(6000) على السلسلة الرئيسية. قم بتشغيل التطبيق عبر Debug وبعد 5 ثوانٍ سترى حوار ANR. تحقق من ظهور سجل ANR مع تتبع في logcat.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.