מערכת Android מבצעת רינדור של ממשק המשתמש על ידי יצירת פריים מהאפליקציה והצגתו במסך. אם האפליקציה סובלת מרינדור איטי של ממשק המשתמש, המערכת נאלצת לדלג על פריימים. במצב כזה, המשתמש רואה הבהוב חוזר במסך, שנקרא jank.
כשמתרחשת בעיה של jank, בדרך כלל זה קורה בגלל האטה או חסימה של קריאה אסינכרונית ב-thread של ממשק המשתמש (ברוב האפליקציות, זה ה-thread הראשי). אפשר להשתמש במעקב מערכת כדי לזהות את מקור הבעיה.
זיהוי של תנועות קופצות ב-Android מגרסה 12 ואילך
במכשירים עם Android 12 (API ברמה 31) ומעלה, מעקב שנתפס מוצג במסלול Janky frames בחלונית Display ב-CPU Profiler.
כדי לזהות בעיות בממשק (jank):
ב-Android Studio, בוחרים באפשרות View > Tool Windows > Profiler (תצוגה > חלונות כלים > כלי לניתוח ביצועים) או לוחצים על Profile (ניתוח ביצועים)
בסרגל הכלים.
אם מופיעה תיבת הדו-שיח Select Deployment Target (בחירת יעד פריסה), בוחרים את המכשיר שבו רוצים לפרוס את האפליקציה לצורך יצירת פרופיל. אם חיברתם מכשיר באמצעות USB אבל הוא לא מופיע ברשימה, צריך לוודא שהפעלתם ניפוי באגים ב-USB.
לוחצים במקום כלשהו בציר הזמן של CPU כדי לפתוח את הכלי CPU Profiler.
בתפריט ההגדרות של CPU Profiler, בוחרים באפשרות System Trace ולוחצים על Record. אחרי שמסיימים את האינטראקציה עם האפליקציה, לוחצים על עצירה.
המסלול Janky frames אמור להופיע בקטע Display. כברירת מחדל, הכלי Profiler מציג רק פריימים עם תנודות כפריימים שמועמדים לבדיקה. בכל פריים עם גמגום, החלק האדום מדגיש את משך הזמן שחלף מהמועד האחרון לעיבוד הפריים.
אחרי שמוצאים פריים עם תנועה קופצנית, לוחצים עליו. אפשר גם להקיש על M כדי לשנות את רמת הזום ולהתמקד בפריים שנבחר. האירועים הרלוונטיים מודגשים ב-threads האלה: ה-thread הראשי, RenderThread ו-GPU completion.
אפשר גם לראות את כל המסגרות או פירוט של זמן העיבוד. כדי לעשות זאת, מסמנים את תיבות הסימון All Frames (כל המסגרות) ו-Lifecycle (מחזור חיים), בהתאמה.
זיהוי של תנועות קופצות ב-Android 11
במכשירים עם Android 11 (רמת API 30), טראס שצולם מוצג בקטע Frame Lifecycle ב-CPU Profiler.
הקטע Frame Lifecycle מכיל את שם השכבה וארבעה טראקים. כל רכיב מייצג שלב אחד בצינור הרינדור של המסגרת. הרכיבים של מחזור החיים של מסגרת הם:
- Frame Lifecycle (Layer name): שם השכבה מופיע בסוגריים בשם הקטע. שכבה היא יחידה אחת של קומפוזיציה.
- Application: המסלול הזה מראה את הזמן שחלף מהרגע שבו המאגר הוצא מהתור על ידי האפליקציה ועד הרגע שבו הוא הוכנס בחזרה לתור. בדרך כלל, זה תואם לאירועי המעקב ב-
RenderThread
. - המתנה ל-GPU: בטראק הזה מוצג משך הזמן שהמאגר היה בבעלות ה-GPU. זהו הזמן שחולף מרגע שליחת המאגר אל ה-GPU ועד שה-GPU מסיים את העבודה שלו על המאגר. הנתון הזה לא מציין שיחידת ה-GPU פעלה רק על המאגר הזה במהלך הזמן הזה. כדי לקבל מידע מפורט על מה שה-GPU עובד עליו במהלך פרק זמן מסוים, מומלץ להשתמש ב-Android GPU Inspector.
- הרכב: במסלול הזה מוצג הזמן שחל מהרגע שבו SurfaceFlinger מתחבר למאגר ושולח אותו להרכבה, ועד שהמאגר נשלח לתצוגה.
- פריימים שמוצגים: בטראק הזה מוצג משך הזמן שבו הפריימים הוצגו במסך.
בקטע מחזור החיים של פריים מוסבר איך מאגר פריים עובר בין שלבים שונים בצינור העיבוד. המסגרות מסומנות בצבעים לפי מספר המסגרת, כדי שיהיה קל יותר לעקוב אחרי מסגרת מסוימת.
ב-Android Studio מוצגים גם כל הפריימים בטבלת המעקב בפורמט של טבלה בכרטיסייה All Frames.
העמודות Frame #, Application, Wait for GPU ו-Composition מייצגות את אותם נתונים כמו הרצועות בקטע Frame Lifecycle שמופיע למעלה. העמודה משך הפריים מייצגת את הזמן שחלף מתחילת האפליקציה ועד לתחילת הפריימים שמוצגים. זהו משך הזמן שנדרש כדי לעבד פריים מקצה לקצה.
אפשר למיין את טבלת הפריימים לפי כל עמודה כדי למצוא במהירות את הפריימים הקצרים או הארוכים ביותר. בטבלה יש גם אמצעי בקרה של חלוקה לדפים, שעוזרים לנווט בין מאות מסגרות.
כדי לזהות ולחקור את הבעיה של תנועה קופצנית ב-Android 11, מבצעים את השלבים הבאים:
ממיינים את הטבלה All Frames לפי העמודה Application בסדר יורד, כך שהפריימים שלוקח להם הכי הרבה זמן להופיע יוצגו ראשונים.
מוצאים את המסגרות שפועלות הכי הרבה זמן ובוחרים את השורה בטבלה. הפעולה הזו מגדילה את התצוגה של המסגרת שנבחרה בתצוגת ציר הזמן שמימין.
מחפשים שרשורים רלוונטיים בקטעים Frame Lifecycle ו-Threads.
זיהוי של jank ב-Android מגרסה 10 ומטה
במכשירים עם Android מגרסה 10 (רמת API 29) ומטה, מידע רלוונטי על צינור הגרפיקה של מערכת ההפעלה מוצג בקטע יחיד במעקב המערכת של CPU Profiler שנקרא Display.
- מסגרות: בקטע הזה מוצגים שרשור ממשק המשתמש ואירועי מעקב
RenderThread
באפליקציה. אירועים שנמשכים יותר מ-16 אלפיות השנייה צבועים באדום כדי להדגיש מסגרות פוטנציאליות עם תנועה קופצנית, כי הם חורגים מהזמן המוקצב לעיבוד ב-60 פריימים לשנייה (fps). - SurfaceFlinger: בקטע הזה מוצג מתי SurfaceFlinger מעבד את מאגרי המסגרות. SurfaceFlinger הוא תהליך מערכת שאחראי לשליחת מאגרי נתונים לתצוגה.
- VSYNC: בקטע הזה מוצג VSYNC, אות שמסנכרן את צינור התצוגה. בטראק מוצג האות VSYNC-app, שמראה מתי האפליקציה מתחילה מאוחר מדי. בדרך כלל, זה קורה כי ה-thread של ממשק המשתמש עמוס. היא גורמת להבהוב גלוי במסך במהלך אנימציה, ומוסיפה חביון קלט נוסף עד שהאנימציה או הגלילה מסתיימות. הנתון הזה חשוב במיוחד לצפייה במסכים עם קצב רענון גבוה, כי יכול להיות שהם יתרחשו בתדירות גבוהה יותר מ-60 פעמים בשנייה או בקצב משתנה.
- BufferQueue: בקטע הזה מוצג מספר מאגרי הפריימים שנמצאים בתור וממתינים לצריכה על ידי SurfaceFlinger. באפליקציות שמופעלות במכשירים עם Android 9 (רמת API 28) ומעלה, אפשר לראות את מספר המאגרים של BufferQueue (
0
,1
או2
) של משטח האפליקציה. BufferQueue יכול לעזור לכם להבין את המצב של מאגרי התמונות כשהם עוברים בין רכיבי הגרפיקה של Android. לדוגמה, ערך של2
מציין שהאפליקציה משתמשת כרגע בזיכרון משולש, מה שגורם לזמן אחזור נוסף של קלט.
בקטע Display מוצגים אותות שימושיים לזיהוי בעיות פוטנציאליות בממשק (jank). לדוגמה, אם השרשור של ממשק המשתמש או RenderThread
נמשך יותר מ-16 אלפיות השנייה. כדי לבדוק פרטים מדויקים לגבי הגורם לבעיות בממשק, אפשר לעיין בקטע Threads, שבו מוצגים השרשורים שרלוונטיים לעיבוד התמונה של ממשק המשתמש.
באיור שלמעלה, בקטע Threads מוצגים שרשור ממשק המשתמש (java.com.google.samples.apps.iosched
), RenderThread
והשרשור GPU completion
. אלה השרשורים שרלוונטיים לרינדור של ממשק המשתמש ועשויים לתרום לבעיות בביצועים.
כדי לזהות jank ב-Android מגרסה 10 ומטה, פועלים לפי השלבים הבאים:
מעיינים בטראק Frames (מסגרות) בDisplay (תצוגה). המסגרות האדומות הן מועמדות לבדיקה.
אם מזהים פריים עם תנועה קופצנית, אפשר להגדיל אותו על ידי הקשה על
W
או גלגול גלגל העכבר תוך כדי לחיצה על Control (Command ב-macOS). ממשיכים להתקרב עד שמתחילים לראות את אירועי המעקב בשרשור של ממשק המשתמש ואתRenderThread
.באיור שלמעלה,
Choreographer#doFrame
מופיע כששרשור ממשק המשתמש קורא ל-Choreographer
כדי לתאם בין אנימציה, פריסת תצוגה, ציור תמונה ותהליכים קשורים.DrawFrames
הערך הזה מציין מתיRenderThread
יוצר פקודות ציור בפועל ל-GPU.אם אתם רואים אירוע ארוך במיוחד של מעקב, אתם יכולים להגדיל את התצוגה כדי לגלות מה גרם לעיבוד האיטי. באיור שלמעלה מוצג
inflate
בשרשור של ממשק המשתמש, כלומר האפליקציה מבזבזת זמן על הרחבת הפריסה. כשמגדילים את התצוגה של אחד מאירועיinflate
, אפשר לראות בדיוק כמה זמן לוקח לכל רכיב בממשק המשתמש, כמו שמוצג בהמשך.
מידע נוסף
מידע נוסף על צמצום ה-jank זמין במאמר מקורות נפוצים ל-jank.