ANR در توسعه اندروید — چیست، علل و روش‌های رفع

نویسنده: IT Sectr منتشر شده: 2026-03-28 زمان مطالعه: 9 دقیقه

ANR (Application Not Responding) — یک اعلان سیستمی اندروید است که هنگامی ظاهر می‌شود که برنامه بیش از ۵ ثانیه به ورودی کاربر پاسخ نمی‌دهد. به گفته Android Developers، علت اصلی عملیات طولانی در رشته اصلی است که پردازش لمس‌ها و رندر رابط را مسدود می‌کند. درک مکانیزم‌های ANR برای هر توسعه‌دهنده اندروید جهت ایجاد برنامه‌های پاسخگو ضروری است.

نکات اصلی

  • ANR — هشدار سیستمی اندروید هنگام هنگ کردن برنامه بیش از ۵ ثانیه
  • رشته اصلی (رشته UI) — تنها جایی که مسدود شدن به ANR منجر می‌شود
  • InputDispatcher — مؤلفه سیستمی که تأخیر ورودی را ثبت و ANR را شروع می‌کند
  • traces.txt — فایل کلیدی برای تشخیص علت هنگ در دستگاه
  • StrictMode — ابزار داخلی اندروید برای تشخیص عملیات طولانی در رشته UI

ANR چیست

ANR (Application Not Responding) — یک کادر محاوره‌ای سیستم عامل اندروید است که وقتی برنامه از پاسخ به ورودی کاربر بازمی‌ایستد ظاهر می‌شود. سیستم زمان پردازش رویدادها را از طریق InputDispatcher ردیابی می‌کند: اگر لمس یا فشار دکمه در عرض ۵ ثانیه پردازش نشود، اندروید کادر محاوره‌ای با پیشنهاد بستن یا منتظر ماندن برنامه نشان می‌دهد.

مکانیزم ANR از تجربه کاربری در برابر برنامه‌های هنگ کرده محافظت می‌کند. اندروید به یک برنامه اجازه نمی‌دهد کل سیستم را مسدود کند — برخلاف سیستم‌های دسکتاپ، پلتفرم موبایل به اجبار زمان پردازش رویدادها را محدود می‌کند. BroadcastReceiver محدودیت ۱۰ ثانیه و سرویس foreground محدودیت ۲۰ ثانیه دارد.

ANR یک استثنا در کد نیست — این یک مکانیزم سیستمی در سطح فرآیندهای لینوکس است. اندروید سیگنال SIGQUIT را به فرآیند می‌فرستد، پس از آن سیستم پشته فراخوانی همه رشته‌ها را در فایل traces.txt ذخیره می‌کند. توسعه‌دهنده ANR را نه به عنوان یک استثنای catch، بلکه به عنوان گزارشی پس از راه‌اندازی مجدد برنامه دریافت می‌کند. در اندروید ۱۱+ API ApplicationExitInfo ظاهر شد که به شما امکان می‌دهد علت خاتمه فرآیند از جمله ANR را به صورت برنامه‌ریزی شده به دست آورید — این کار جمع‌آوری آمار را بدون تجزیه دستی traces.txt ساده می‌کند.

علل اصلی ANR

پنج دسته عملیات به طور پایدار به ANR در برنامه‌های اندروید منجر می‌شوند. هر یک از آنها رشته اصلی را مسدود می‌کند و به سیستم اجازه پردازش رویدادهای ورودی و بازترسیم صفحه را نمی‌دهد.

درخواست‌های شبکه در رشته اصلی

درخواست‌های HTTP همزمان که در رشته UI اجرا می‌شوند — شایع‌ترین علت ANR در توسعه‌دهندگان مبتدی. حتی یک درخواست سریع به سرور ممکن است ۱–۳ ثانیه طول بکشد و در اتصال ضعیف — ۳۰ ثانیه یا بیشتر. اندروید از API 11 به بعد به صراحت عملیات شبکه را در رشته اصلی ممنوع می‌کند و NetworkOnMainThreadException را پرتاب می‌کند.

برای فراخوانی‌های ناهمگام از Coroutines یا RxJava استفاده کنید. کوروتین‌ها با Dispatchers.IO درخواست را در رشته پس‌زمینه اجرا می‌کنند و نتیجه را از طریق Dispatchers.Main به رشته اصلی منتقل می‌کنند. این امر مسدود شدن رشته UI توسط عملیات شبکه را کاملاً از بین می‌برد.

kotlin
fun fetchUserData() {
    CoroutineScope(Dispatchers.Main).launch {
        val result = withContext(Dispatchers.IO) {
            api.getUserData() // عملیات پس‌زمینه
        }
        updateUI(result) // نتیجه در رشته اصلی
    }
}

محاسبات فشرده در رشته UI

پردازش آرایه‌های بزرگ داده، تجزیه JSON یا XML، کار مستقیم با bitmap در رشته اصلی — دومین علت شایع ANR. حتی ۳۰۰ میلی‌ثانیه کار مداوم رشته UI بدون بازگشت به حلقه رویداد باعث تأخیر قابل توجه در رندر می‌شود و مقدار مرزی ۵ ثانیه به عنوان ANR ثبت می‌شود.

WorkManager و سرویس‌های پس‌زمینه برای انتقال محاسبات سنگین از رشته اصلی طراحی شده‌اند. برای انتقال داده‌ها به صورت تکه‌ای بدون مسدود کردن UI از AsyncTask (منسوخ شده)، ListenableFuture یا Kotlin Flow استفاده کنید.

قفل‌های همگام‌سازی و بن‌بست

بن‌بست (Deadlock) زمانی رخ می‌دهد که دو رشته قفل‌ها را نگه داشته و منتظر یکدیگر باشند. اگر یکی از رشته‌ها اصلی باشد، سیستم دقیقاً پس از ۵ ثانیه ANR را ثبت می‌کند. Thread.join()، CountDownLatch.await() و بلوک‌های synchronized که از رشته UI فراخوانی می‌شوند خطر بن‌بست را به همراه دارند.

از هرگونه عملیات مسدودکننده در رشته اصلی خودداری کنید. به جای synchronized از ConcurrentHashMap، به جای Thread.join() از کوروتین‌ها با async/await استفاده کنید. این قانون برای هر زبانی در اندروید معتبر است: Java، Kotlin یا C++ از طریق JNI.

کار طولانی BroadcastReceiver

BroadcastReceiver به طور پیش‌فرض در رشته اصلی اجرا می‌شود. اگر onReceive() بیش از ۱۰ ثانیه مشغول باشد، اندروید ANR را نشان می‌دهد. بارگذاری داده از پایگاه داده یا شبکه درون onReceive راهی تضمینی به سوی هنگ است.

درون BroadcastReceiver برای تغییر به رشته پس‌زمینه از goAsync() یا registerReceiver با getBackgroundBroadcastReceiver() استفاده کنید. این امکان پردازش رویدادها را بدون مسدود کردن UI فراهم می‌کند.

ContentProvider و SQLite در رشته اصلی

پرس‌وجوهای سنگین به ContentProvider یا کار مستقیم با SQLite در رشته UI — علت کمتر آشکار اما شایع ANR. در هنگام مهاجرت پایگاه داده یا درج انبوه هزاران رکورد، زمان اجرا ممکن است از محدودیت ۵ ثانیه فراتر رود.

تمام عملیات پایگاه داده را از طریق Room با توابع suspend به رشته‌های پس‌زمینه منتقل کنید. Room به طور خودکار بررسی می‌کند که پرس‌وجو در رشته اصلی اجرا نشود و در صورت نقض استثنا پرتاب می‌کند.

چگونه ANR را تشخیص دهیم

تشخیص ANR با اشکال‌زدایی استثناهای معمولی متفاوت است — شما نمی‌توانید ANR را در try-catch بگیرید. منبع اصلی اطلاعات فایل traces.txt است که اندروید در لحظه هنگ ایجاد می‌کند.

traces.txt حاوی پشته فراخوانی همه رشته‌های برنامه در لحظه ANR است. برای خواندن فایل از یک دستگاه واقعی، دستور adb bugreport را اجرا کنید که گزارش کامل سیستم شامل تمام ANRهای اخیر را جمع‌آوری می‌کند. برای شبیه‌ساز، فایل در /data/anr/traces.txt در دسترس است. پشته فراخوانی نشان می‌دهد که کدام متد در لحظه مسدود شدن در رشته اصلی اجرا می‌شد.

text
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt

Google Play Console بخش ANR & Crash را با گزارش‌های تجمیع‌شده و فراوانی خطاها ارائه می‌دهد. برای هر ANR پشته فراخوانی و آمار بر اساس دستگاه‌ها نشان داده می‌شود: مدل، نسخه اندروید، منطقه. این امکان شناسایی ANRهایی را که به دستگاه‌ها یا نسخه‌های خاص سیستم وابسته هستند فراهم می‌کند.

Android Studio از سال ۲۰۲۱ شامل ANR Watchdog در پروفایلر است. اگر رشته اصلی بیش از زمان آستانه پاسخ ندهد، به طور خودکار dump رشته‌ها را ثبت می‌کند. ابزار خط زمانی رویدادها را نشان می‌دهد: چه عملیاتی راه‌اندازی شده، چه متدهایی اجرا شده و مسدود شدن در چه مرحله‌ای رخ داده است.

چگونه از ANR جلوگیری کنیم

پیشگیری ANR بر یک قانون اساسی استوار است: رشته اصلی باید فقط رویدادهای UI را پردازش کند. هر عملیاتی که بیش از ۱۶ میلی‌ثانیه (زمان یک فریم) طول بکشد باید در رشته پس‌زمینه اجرا شود.

StrictMode — بررسی خودکار

StrictMode — ابزار داخلی اندروید برای تشخیص ANRهای بالقوه در مرحله توسعه. آن را در Application.onCreate() با پرچم‌هایی برای عملیات دیسڥ و شبکه فعال کنید. در صورت نقض، StrictMode استثنا پرتاب می‌کند یا در logcat می‌نویسد.

kotlin
if (BuildConfig.DEBUG) {
    StrictMode.ThreadPolicy.Builder()
        .detectDiskReads()
        .detectDiskWrites()
        .detectNetwork()
        .penaltyLog()
        .build()
        .let { StrictMode.setThreadPolicy(it) }
}

الگوهای ناهمگام: Coroutines و RxJava

Kotlin Coroutines — روش استاندارد کار ناهمگام در برنامه‌های مدرن اندروید. اصل اساسی: عملیات ورودی-خروجی روی Dispatchers.IO اجرا می‌شوند، نتیجه برای به‌روزرسانی UI به Dispatchers.Main منتقل می‌شود. برای سناریوهای Flow از Dispatchers.Default برای وظایف فشرده CPU استفاده کنید.

RxJava در پروژه‌های قدیمی محبوب باقی می‌ماند. subscribeOn(Schedulers.io()) و observeOn(AndroidSchedulers.mainThread()) — حداقل مجموعه برای جلوگیری از ANR. قانون اصلی یکسان است: هیچ Observable یا Flowable نباید داده‌ها را از رشته اصلی emit کند.

نظارت در تولید

Firebase Crashlytics از نسخه SDK 18.4.0 نظارت ANR را خارج از جعبه پشتیبانی می‌کند. برای اندروید ۱۱+ Crashlytics از API سیستمی ApplicationExitInfo استفاده می‌کند که علت دقیق خاتمه را ارائه می‌دهد: ANR، Crash یا کشته شدن توسط سیستم. کلیدهای سفارشی با پارامترهای صفحه و وضعیت را برای تحلیل زمینه‌ای فعال کنید.

ابزارهای تشخیص ANR

پنج ابزار تمام مراحل کار با ANR را پوشش می‌دهند: از اشکال‌زدایی در ایستگاه کاری تا نظارت در تولید. هر ابزار وظیفه خود را حل می‌کند و داده‌هایی را برای سناریوهای مختلف فراهم می‌کند.

ابزارهدففرمت داده
StrictModeتشخیص در مرحله توسعهLogcat / Exception
ANR Watchdog (Android Studio)ردیابی بلادرنگThread dump + timeline
Google Play Consoleآمار تجمیعیANR rate + stack traces
Firebase Crashlyticsنظارت تولیدApplicationExitInfo
adb bugreportگزارش کامل سیستمtraces.txt + logcat + dmesg

هر ابزار جایگاه خود را دارد: StrictMode نقض‌های آشکار را در مراحل اولیه می‌گیرد، Crashlytics فراوانی واقعی ANR را در کاربران نشان می‌دهد، و adb bugreport کامل‌ترین تصویر را برای موارد پیچیده ارائه می‌دهد. برای پوشش کامل آنها را ترکیب کنید.

Firebase Performance Monitoring

Firebase Performance زمان پاسخ رشته UI را ردیابی می‌کند و به طور خودکار برای عملیات مشکوک طولانی ره‌گیری ایجاد می‌کند. اگر رشته اصلی بیش از ۵۰۰ میلی‌ثانیه مسدود شود، Performance یک ره‌گیری سفارشی با نام متد مقصر ثبت می‌کند. این امکان تشخیص سناریوهای ANR را بدون مشارکت کاربر و قبل از بحرانی شدن آنها فراهم می‌کند.

ادغام با Firebase Crashlytics تصویر کاملی می‌دهد: Performance کندی‌های قبل از ANR را نشان می‌دهد و Crashlytics — خود واقعیت هنگ. در Firebase Console برای رویداد ANR rate بالای ۰٫۱٪ هشدار تنظیم کنید و قبل از شکایت‌های جمعی کاربران از مشکلات جدید مطلع خواهید شد.

سؤالات متداول

ANR چه تفاوتی با Crash دارد؟

ANR — یک هنگ است که در آن برنامه پاسخ نمی‌دهد اما در حافظه باقی می‌ماند. Crash — پایان کامل اضطراری با خروج از فرآیند. ANR را می‌توان «تحمل کرد» اگر سیستم یا کاربر منتظر پاسخ بمانند، اما Crash همیشه برنامه را خاتمه می‌دهد.

آیا می‌توان ANR را با try-catch گرفت؟

خیر. ANR یک استثنای Java/Kotlin نیست، بلکه یک سیگنال سیستم در سطح فرآیندها است (SIGQUIT). توسعه‌دهنده نمی‌تواند آن را در کد برنامه پردازش کند. تنها راه واکنش به ANR — تجزیه و تحلیل گزارش‌ها پس از راه‌اندازی مجدد است.

چرا ANR در بعضی دستگاه‌ها ظاهر می‌شود اما در بعضی دیگر نه؟

عملکرد دستگاه، نسخه اندروید، بار CPU و تعداد فرآیندهای پس‌زمینه بر احتمال ANR تأثیر می‌گذارند. در دستگاه‌های ضعیف، همان عملیات ممکن است ۲–۳ برابر بیشتر طول بکشد و از محدودیت ۵ ثانیه فراتر رود.

محدودیت زمانی BroadcastReceiver تا ANR چقدر است؟

۱۰ ثانیه برای BroadcastReceiver معمولی در onReceive(). برای سرویس‌های foreground محدودیت ۲۰ ثانیه و برای ContentProvider محدودیت صریحی وجود ندارد، اما مسدود شدن رشته اصلی بیش از ۵ ثانیه همچنان ANR ایجاد می‌کند.

اگر ANR به ندرت رخ دهد و قابل تکرار نباشد چه باید کرد؟

در تمام buildهای debug StrictMode را فعال کنید، نظارت را از طریق Firebase Crashlytics اضافه کنید و هنگام وقوع ANR از adb bugreport استفاده کنید. ANRهای نامنظم اغلب با شرایط رقابت (race condition) یا وضعیت‌های خاص شبکه مرتبط هستند.

خلاصه

  • ANR — مکانیزم سیستمی اندروید که هنگام مسدود شدن رشته اصلی بیش از ۵ ثانیه فعال می‌شود
  • رشته اصلی باید فقط به UI بپردازد — تمام عملیات دیگر به رشته‌های پس‌زمینه منتقل می‌شوند
  • تشخیص ANR از طریق traces.txt، Google Play Console و Firebase Crashlytics انجام می‌شود
  • StrictMode ANRهای بالقوه را در مرحله توسعه بدون اجرا در دستگاه واقعی تشخیص می‌دهد
  • Coroutines با Dispatchers.IO — روش استاندارد کار ناهمگام در پروژه‌های مدرن اندروید
  • BroadcastReceiver برای کار بیش از ۱۰ ثانیه نیاز به goAsync() یا ثبت‌کننده پس‌زمینه دارد
  • ANR در تولید از طریق Crashlytics و API داخلی ApplicationExitInfo در اندروید ۱۱ و بالاتر نظارت می‌شود

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید