ANR و فریز: وقتی برنامه نمیافتد ولی کار هم نمیکند

بدترین حالت یک اپلیکیشن این نیست که بسته شود. این است که باز بماند و هیچ کاری نکند.
وقتی برنامه کرش میکند، دستکم تکلیف روشن است: بسته شد، دوباره بازش میکنی. ولی صفحهای که یخ زده و دکمهای که به لمس جواب نمیدهد، کاربر را در حالت بدتری میگذارد — منتظر. و بعد از چند ثانیه نتیجه میگیرد که برنامه خراب است.
روی اندروید اسم رسمیاش ANR است: «برنامه پاسخ نمیدهد». روی iOS به آن hang میگویند. مکانیزم زیربنایی هر دو یکی است.
نخ اصلی، و چرا همهچیز به آن برمیگردد
هر اپلیکیشن موبایل یک نخ دارد که فقط او اجازه دارد رابط کاربری را بکشد و به لمس جواب بدهد. اگر کاری روی آن نخ طول بکشد، در آن مدت هیچچیز حرکت نمیکند: نه انیمیشن، نه اسکرول، نه واکنش به دکمه.
سیستمعامل صبر میکند. اگر مدت زیادی بگذرد، روی اندروید کادر «برنامه پاسخ نمیدهد» را نشان میدهد و پیشنهاد بستن میکند.
آستانهای که ابزارها معمولاً برای گزارش استفاده میکنند ۵ ثانیه است، و بیشتر آنها اجازهٔ تغییرش را هم میدهند. ولی این عدد را با آستانهٔ آزار کاربر اشتباه نگیرید: کاربر خیلی زودتر از پنج ثانیه ناراضی میشود. زیر ۱۰۰ میلیثانیه آنی حس میشود؛ بالای یک ثانیه، کند؛ بالای سه ثانیه، خراب.
چه چیزهایی نخ اصلی را میبندند
فهرست متهمان تقریباً همیشه همین است:
درخواست شبکه روی نخ اصلی. امروز چارچوبها معمولاً جلویش را میگیرند، ولی هنوز در کد قدیمی پیدا میشود.
پایگاه دادهٔ محلی. پرسوجویی که روی ۵۰ ردیف فوری است، روی ۵۰ هزار ردیف — بعد از دو سال استفادهٔ کاربر — نیست. این پرتکرارترین موردی است که دیدهایم و در آزمون دیده نمیشود، چون دستگاه آزمون دادهاش تازه است.
خواندن و نوشتن فایل، مخصوصاً JSON بزرگ در زمان راهاندازی.
رمزگشایی تصویر؛ تصویر بزرگی که قبل از نمایش باید باز شود.
و چیزی که کمتر به آن فکر میشود: قفل. نخ اصلی منتظر قفلی میماند که نخ دیگری گرفته. اینجا نخ اصلی هیچ کار سنگینی نمیکند — فقط منتظر است — و همین موارد سختترین موارد برای پیدا کردناند.
چرا در گزارش خرابی معمولی نمیآید
این نکتهٔ اصلی است. برنامه نمرده، پس هیچ کرشی ثبت نمیشود. گزارش خرابی شما ساکت است و نرخ نشست بدون خرابیتان عالی، در حالی که بخشی از کاربرانتان هر روز به صفحهٔ یخزده نگاه میکنند.
پس ANR سنجه و ابزار جداگانه لازم دارد. اگر امروز نمیدانید نرخ ANR اپلیکیشنتان چقدر است، این یعنی صفر نیست — یعنی اندازهگیری نشده.
فروشگاه هم نگاه میکند
ANR فقط مسئلهٔ تجربهٔ کاربر نیست. فروشگاههای اپلیکیشن این را بهعنوان سنجهٔ کیفیت میسنجند و اگر نرخ ANR از حدی بگذرد، دیده شدن برنامه در فهرستها آسیب میبیند.
یعنی این عدد، برخلاف بیشتر سنجههای فنی، اثر مستقیم تجاری دارد — و همان چیزی است که باعث میشود بشود بودجهاش را از مدیر گرفت.
چطور اندازه بگیریم
AppMetrica ANR را روی هر دو اندروید و iOS
جمع میکند و از ایران هم قابل استفاده است. آستانهٔ پیشفرضش پنج ثانیه است و
میشود عوضش کرد — روی اندروید مثلاً با .withAnrMonitoringTimeout(7).
یک نکتهٔ مهم برای انتظارات درست: گزارش ANR آن تعداد رویداد، تعداد دستگاه، درصد دستگاهها، نسخهٔ کشف و آخرین بازتولید را نشان میدهد. یعنی مبنایش دستگاه است، نه نشست. پس «نرخ ANR» به آن شکلی که در داشبورد فروشگاه میبینید را مستقیم نمیدهد. این ایراد نیست، ولی اگر انتظارش را داشته باشید و نباشد، وقت تلف میکنید.
در کنارش، داشبورد خود فروشگاه را هم نگاه کنید. آن، دادهٔ مرجع برای تصمیمهای انتشار است.
پیدا کردن علت
وقتی رویدادی ثبت شد، چیزی که دستتان است وضعیت نخها در لحظهٔ گیر کردن است. سه گام که معمولاً جواب میدهد:
اول نخ اصلی را بخوانید و ببینید در چه تابعی متوقف شده. اگر منتظر قفل است، دنبال نخی بگردید که آن قفل را دارد — آن نخ، مقصر واقعی است، نه نخ اصلی.
بعد ببینید در چه نسخهای شروع شده. اگر نسخهٔ مشخصی است، تغییرات همان انتشار را نگاه کنید؛ سلامت انتشار دقیقاً برای همین است.
و بعد توزیع دستگاهها را ببینید. اگر فقط روی دستگاههای ضعیف است، مسئله کارایی است نه منطق — و راهش با فهرست کارایی اپلیکیشن موبایل یکی است.
کاری که از اول باید بکنید
پیشگیری اینجا واقعاً از درمان ارزانتر است، چون قاعدهاش یکی است و ساده:
هر کاری که ممکن است طول بکشد، روی نخ اصلی نباشد. شبکه، پایگاه داده، فایل، رمزگذاری، پردازش تصویر. بدون استثنا — حتی وقتی «الان که سریع است».
بیشتر چارچوبهای امروزی حالت سختگیرانه دارند که در زمان توسعه، کار مسدودکننده روی نخ اصلی را فریاد میزند. روشنش کنید. ارزانترین ابزار این فهرست است و بیشتر تیمها نمیدانند وجود دارد.
و یک آزمون که هیچ ابزاری جایش را نمیگیرد: برنامه را روی ضعیفترین دستگاهی که پشتیبانی میکنید و با حسابی که چند سال داده دارد باز کنید. اگر فقط روی گوشی تازهٔ توسعهدهنده با حساب خالی تست میشود، ANR را در تولید کشف خواهید کرد — یعنی جایی که کاربر کشفش میکند.