
איור 1. תיבת דו-שיח של ANR שמוצגת למשתמש.
במסמך הזה מוסבר איך מערכת Android קובעת אם אפליקציה לא מגיבה, ומוסבר איך לשמור על אפליקציה רספונסיבית.
לא משנה כמה הקוד כתוב היטב, יכול להיות שהאפליקציה עדיין תרגיש איטית, תיתקע, תיקפא לפרקי זמן משמעותיים או שייקח לה יותר מדי זמן לעבד קלט. אם האפליקציה פועלת בחזית ולא מגיבה, מוצג למשתמש דו-שיח של 'האפליקציה לא מגיבה' (ANR), כמו שמוצג באיור 1. בתיבת הדו-שיח של ANR, המשתמש יכול לצאת מהאפליקציה בכוח. אם האפליקציה לא בחזית, היא נעצרת בשקט. חשוב מאוד לתכנן את האפליקציה כך שתהיה רספונסיבית כדי לצמצם את מספר תיבות הדו-שיח של ANR.
טריגרים של ANR
באופן כללי, המערכת מציגה שגיאת ANR אם אפליקציה לא יכולה להגיב לקלט של משתמשים בשרשור הראשי – שנקרא גם שרשור ה-UI – ומונעת מהמערכת לעבד אירועי קלט של משתמשים.
לדוגמה, יכול להיות שיתרחש ANR אם אפליקציה מבצעת פעולת חסימה של קלט/פלט, כמו גישה לרשת, בשרשור ממשק המשתמש. דוגמה נוספת היא כשבאפליקציה מושקע יותר מדי זמן בבניית מבנה מורכב בזיכרון או בחישוב המהלך הבא במשחק בשרשור של ממשק המשתמש.
ב-Android, שירותי המערכת ActivityManager
וWindowManager
עוקבים אחרי מהירות התגובה של האפליקציה. מערכת Android מציגה את תיבת הדו-שיח ANR לאפליקציה כשהיא מזהה אחד מהתנאים הבאים:
- אין תגובה לאירוע קלט – כמו אירועים של הקשת מקש או הקשה על המסך – תוך 5 שניות.
- אם
BroadcastReceiver
לא מסיימת את ההרצה תוך 10 עד 20 שניות, עבור כוונות בחזית. מידע נוסף זמין במאמר בנושא פסק זמן של מקלט שידורים.
איך להימנע ממקרי ANR
אלה טיפים כלליים שיעזרו לכם להימנע מ-ANR. לפרטים נוספים על אבחון וניפוי באגים של סוגים שונים של ANR, אפשר לעיין בדפים האחרים בקטע הזה.
חשוב לוודא שה-thread הראשי לא חסום אף פעם, ולהשתמש ב-threads בצורה אסטרטגית.
אל תבצעו פעולות חסימה או פעולות ארוכות בשרשור הראשי של האפליקציה. במקום זאת, כדאי ליצור thread של worker ולבצע בו את רוב העבודה.
כדאי לנסות לצמצם את התחרות על הנעילה בין ה-thread הראשי לבין threads אחרים.
כדאי לצמצם את העבודה שלא קשורה לממשק המשתמש בשרשור הראשי, למשל כשמטפלים בשידורים או מפעילים שירותים. כל שיטה שמופעלת בשרשור של ממשק המשתמש צריכה לבצע כמה שפחות פעולות בשרשור הזה. בפרט, הפעילויות צריכות לבצע כמה שפחות פעולות בהגדרות שלהן בשיטות מחזור חיים מרכזיות, כמו
onCreate()
ו-onResume()
. מידע נוסף על פתרונות זמינים לתזמון עבודה בשרשור ברקע ולתקשורת חזרה עם ממשק המשתמש מופיע במאמר סקירה כללית על עבודה ברקע.צריך להיזהר כשמשתפים מאגרי שרשורים בין רכיבים. אל תשתמשו באותם שרשורים לפעולות שעלולות לחסום לזמן רב ולמשימות רגישות לזמן, כמו קבלת שידורים.
הפעלה מהירה של האפליקציה. צריך לצמצם את מספר הפעולות האיטיות או פעולות החסימה בקוד ההפעלה של האפליקציה, כמו שיטות שמופעלות במהלך האתחול של Dagger.
אם אתם משתמשים ב-
BroadcastReceiver
, כדאי להריץ את מקלטי השידור בשרשור שאינו השרשור הראשי באמצעותContext.registerReceiver
. מידע נוסף זמין במאמר בנושא ANR ב-BroadcastReceiver.- אם אתם משתמשים ב-
goAsync()
, ודאו שהקריאה ל-PendingResult.finish
מתבצעת במהירות לפני שחלף הזמן הקצוב לתגובה (ANR).
- אם אתם משתמשים ב-
מקרי ANR ב-BroadcastReceiver
זמן הביצוע של BroadcastReceiver
מוגבל כי מקלטי שידור
נועדו לבצע כמויות קטנות של עבודה בדיסקרטיות ברקע, כמו
שמירת הגדרה או רישום של Notification
. לכן, כמו במקרים אחרים של קריאה לשיטות בשרשור ממשק המשתמש, אפליקציות צריכות להימנע מפעולות או מחישובים שעלולים להימשך זמן רב ב-broadcast receiver. במקום לבצע משימות ארוכות דרך השרשור של ממשק המשתמש, מבצעים אותן ברקע לביצוע מאוחר יותר. מידע נוסף על פתרונות אפשריים זמין במאמר סקירה כללית על עבודה ברקע.
בעיה נפוצה נוספת באובייקטים מסוג BroadcastReceiver
מתרחשת כשהם מופעלים בתדירות גבוהה מדי. ביצוע תכוף של פעולות ברקע יכול להפחית את כמות הזיכרון שזמינה לאפליקציות אחרות. מידע נוסף על הפעלה והשבתה יעילות של אובייקטים של BroadcastReceiver
זמין במאמר סקירה כללית על שידורים.
שיפור יכולת התגובה
בדרך כלל, 100 עד 200 אלפיות השנייה הוא הסף שמעבר לו המשתמשים מרגישים שהאפליקציה פועלת לאט. הנה טיפים נוספים שיעזרו לכם לגרום לאפליקציה להיראות מגיבה למשתמשים:
אם האפליקציה מבצעת פעולות ברקע בתגובה לקלט של המשתמש, צריך להציג את ההתקדמות, למשל באמצעות
ProgressBar
בממשק המשתמש.במשחקים ספציפיים, המערכת מבצעת חישובים של מהלכים בשרשור של עובד.
אם לאפליקציה שלכם יש שלב הגדרה ראשוני ארוך, כדאי להציג מסך פתיחה או להציג את התצוגה הראשית במהירות האפשרית. לציין שהטעינה מתבצעת ולמלא את המידע באופן אסינכרוני. בכל מקרה, מומלץ לציין בדרך כלשהי שההתקדמות נמשכת, כדי שהמשתמש לא יחשוב שהאפליקציה קפאה.
כדי לזהות צווארי בקבוק בתגובתיות של האפליקציה, אפשר להשתמש בכלי ביצועים כמו Perfetto ו-CPU Profiler.