1. מבוא
העדכון האחרון: 11 במרץ 2021
למה צריך למדוד את הביצועים של הצפיות?
תצוגות הן חלק חשוב באפליקציות ל-Android, והן משפיעות ישירות על חוויית המשתמש. לדוגמה, הפעילות או ה-Fragment מכילים את ממשק המשתמש שכולל את רכיבי התצוגה שהמשתמשים מקיימים איתם אינטראקציה. המשתמשים לא יכולים לראות את כל התוכן של ממשק המשתמש עד שהוא מצויר לגמרי על המסך. מסכים איטיים או קפואים יפגעו ישירות באינטראקציה של המשתמשים עם האפליקציה וייצרו חוויית משתמש גרועה.
האם מעקב אחרי ביצועים ב-Firebase לא מספק את מדדי הביצועים האלה כברירת מחדל?
מעקב אחר ביצועים ב-Firebase מתעד באופן אוטומטי חלק מנתוני הביצועים, כמו זמן ההפעלה של האפליקציה (כלומר, זמן הטעינה של הפעילות הראשונה בלבד) וביצועי העיבוד של המסך (כלומר, פריימים איטיים וקפואים של פעילויות, אבל לא של רכיבי Fragment). עם זאת, באפליקציות לתעשייה בדרך כלל אין הרבה פעילויות, אלא פעילות אחת וכמה רכיבי Fragment. בנוסף, אפליקציות רבות בדרך כלל מטמיעות תצוגות מותאמות אישית משלהן לתרחישי שימוש מורכבים יותר. לכן, כדאי להבין איך למדוד את זמן הטעינה ואת ביצועי העיבוד של המסך גם של Activities וגם של Fragments, באמצעות מעקב אחר קטעי קוד מותאמים אישית באפליקציה. אפשר להרחיב בקלות את ה-codelab הזה כדי למדוד את הביצועים של רכיבי Custom View.
מה תלמדו
- איך מוסיפים מעקב אחר ביצועים ב-Firebase לאפליקציית Android
- הסבר על טעינה של Activity או Fragment
- איך מטמיעים מעקב אחר קוד מותאם אישית כדי למדוד את זמן הטעינה של פעילות או של Fragment
- הסבר על עיבוד המסך ומהי מסגרת איטית או פריים קפוא
- איך מטמיעים מדדים במעקב אחר קוד מותאם אישית כדי לתעד מסכים איטיים או קפואים
- איך רואים את המדדים שנאספו במסוף Firebase
מה תצטרכו
- Android Studio מגרסה 4.0 ואילך
- מכשיר Android או אמולטור
- Java בגרסה 8 ומעלה
2. תהליך ההגדרה
קבלת הקוד
מריצים את הפקודות הבאות כדי לשכפל את קוד הדוגמה של ה-codelab הזה. תיקייה בשם codelab-measure-android-view-performance תיווצר במחשב:
$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance
אם אין לכם git במחשב, אתם יכולים גם להוריד את הקוד ישירות מ-GitHub.
מייבאים את הפרויקט measure-view-performance-start ל-Android Studio. סביר להניח שיוצגו שגיאות קומפילציה או אזהרה לגבי קובץ google-services.json חסר. נפתור את הבעיה הזו בקטע הבא של השלב הזה.
ב-codelab הזה נשתמש בפלאגין Firebase Assistant כדי לרשום את אפליקציית Android שלנו בפרויקט Firebase ולהוסיף לפרויקט Android את קובצי ההגדרות, הפלאגינים והתלות הדרושים של Firebase – הכול מתוך Android Studio!
קישור האפליקציה ל-Firebase
- כדי לוודא שאתם משתמשים בגרסאות העדכניות של Android Studio ושל Firebase Assistant, עוברים אל Android Studio/Help (עזרה) > Check for updates (בדיקת עדכונים).
- בוחרים באפשרות כלים > Firebase כדי לפתוח את החלונית Assistant (עזרה).

- בוחרים באפשרות מעקב אחר ביצועים כדי להוסיף אותה לאפליקציה, ואז לוחצים על תחילת העבודה עם מעקב אחר ביצועים.
- לוחצים על הלחצן ליצירת פרויקט חדש ומזינים שם לפרויקט (לדוגמה,
Measure Performance Codelab). - לוחצים על המשך.
- אם מוצגת בקשה לעשות זאת, קוראים ומאשרים את התנאים של Firebase, ואז לוחצים על המשך.
- (אופציונלי) מפעילים את העזרה מבוססת-AI במסוף Firebase (שנקראת Gemini ב-Firebase).
- ב-codelab הזה לא צריך להשתמש ב-Google Analytics, ולכן משביתים את האפשרות Google Analytics.
- אחרי כן אמור להופיע תיבת דו-שיח עם האפשרות Connect (קישור) של אפליקציית Firebase החדשה לפרויקט Android Studio.

- ב-Android Studio, בחלונית Assistant, אמור להופיע אישור שהאפליקציה שלכם מחוברת ל-Firebase.

הוספת מעקב אחר ביצועים לאפליקציה
בחלונית Assistant ב-Android Studio, לוחצים על Add Performance Monitoring to your app (הוספת מעקב אחר ביצועים לאפליקציה).
אחרי שתלחצו על Accept Changes (אישור השינויים), אמור להופיע תיבת דו-שיח שבה תתבקשו לסנכרן את האפליקציה עם Android Studio כדי לוודא שכל התלות הנדרשת נוספה.

לבסוף, בחלונית Assistant ב-Android Studio אמורה להופיע הודעה שההגדרה של כל יחסי התלות בוצעה בהצלחה.

בנוסף, אפשר להפעיל רישום ביומן לניפוי באגים לפי ההוראות בשלב '(אופציונלי) הפעלת רישום ביומן לניפוי באגים'. אותן הוראות זמינות גם בתיעוד שגלוי לכולם.
3. הפעלת האפליקציה
אם שילבתם את האפליקציה בהצלחה עם Performance Monitoring SDK, הפרויקט אמור להתקמפל עכשיו. ב-Android Studio, לוחצים על Run (הפעלה) > Run ‘app' (הפעלת האפליקציה) כדי ליצור ולהפעיל את האפליקציה במכשיר Android המחובר או באמולטור.
באפליקציה יש שני לחצנים שמובילים לפעילות ולרכיב Fragment תואמים, כמו בדוגמה הבאה:

בשלבים הבאים של ה-codelab הזה תלמדו איך למדוד את זמן הטעינה ואת ביצועי העיבוד של המסך של הפעילות או של ה-Fragment.
4. הסבר על טעינה של פעילות או של Fragment
בשלב הזה נלמד מה המערכת עושה במהלך הטעינה של Activity או Fragment.
הסבר על טעינת פעילות
במקרה של פעילות, זמן הטעינה מוגדר כזמן שמתחיל מרגע יצירת אובייקט הפעילות ועד לרגע שבו הפריים הראשון מצויר באופן מלא על המסך (זה הרגע שבו המשתמש יראה את ממשק המשתמש המלא של הפעילות בפעם הראשונה). כדי לבדוק אם האפליקציה מוצגת במלואה, אפשר להשתמש בשיטה reportFullyDrawn() כדי למדוד את הזמן שחלף בין הפעלת האפליקציה לבין הצגה מלאה של כל המשאבים והיררכיות התצוגה.
באופן כללי, כשהאפליקציה קוראת ל-startActivity(Intent), המערכת מבצעת אוטומטית את התהליכים הבאים. כל תהליך לוקח זמן עד שהוא מסתיים, וזה מוסיף לפרק הזמן שחלף בין יצירת הפעילות לבין הרגע שבו המשתמש רואה את ממשק המשתמש של הפעילות במסך שלו.

הסבר על טעינה של Fragment
בדומה לפעילות, זמן הטעינה של Fragment מוגדר כזמן שמתחיל מהרגע שבו ה-Fragment מצורף לפעילות המארחת שלו ועד שהפריים הראשון של תצוגת ה-Fragment מצויר באופן מלא על המסך.
5. מדידת זמן הטעינה של פעילות
עיכובים בפריים הראשון עלולים לפגוע בחוויית המשתמש, ולכן חשוב להבין כמה עיכובים בטעינה הראשונית חווים המשתמשים. אפשר להטמיע מעקב אחר קוד בהתאמה אישית כדי למדוד את זמן הטעינה הזה:
- מתחילים את המעקב אחר הקוד בהתאמה אישית (בשם
TestActivity-LoadTime) בכיתת הפעילות ברגע שאובייקט הפעילות נוצר.
TestActivity.java
public class TestActivity extends AppCompatActivity {
// TODO (1): Start trace recording as soon as the Activity object is created.
private final Trace viewLoadTrace = FirebasePerformance.startTrace("TestActivity-LoadTime");
// ...
}
- מבטלים את ה-callback
onCreate()ומקבלים את התצוגה שנוספה באמצעות ה-methodsetContentView().
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Current Activity's main View (as defined in the layout xml file) is inflated after this
setContentView(R.layout.activity_test);
// ...
// TODO (2): Get the View added by Activity's setContentView() method.
View mainView = findViewById(android.R.id.content);
// ...
}
- הוספנו הטמעה של
FistDrawListener, שיש לה שני קריאות חוזרות (callback):onDrawingStart()ו-onDrawingFinish()(בקטע הבא מפורטים פרטים נוספים עלFirstDrawListenerועל מה שיכול להשפיע על הביצועים שלה). מבצעים רישום שלFirstDrawListenerבסוף הקריאה החוזרת של ActivityonCreate(). צריך להפסיק אתviewLoadTraceב-onDrawingFinish()callback.
TestActivity.java
// TODO (3): Register the callback to listen for first frame rendering (see
// "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when View drawing is
// finished.
FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {
@Override
public void onDrawingStart() {
// In practice you can also record this event separately
}
@Override
public void onDrawingFinish() {
// This is when the Activity UI is completely drawn on the screen
viewLoadTrace.stop();
}
});
- מריצים מחדש את האפליקציה. לאחר מכן מסננים את logcat באמצעות מדד מעקב אחר רישום ביומן. מקישים על הלחצן
LOAD ACTIVITYומחפשים יומנים כמו אלה שמופיעים בהמשך:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)
🎉 איזה כיף! הצלחתם למדוד את זמן הטעינה של פעילות ולדווח על הנתונים האלה למעקב אחר ביצועים ב-Firebase. בהמשך ה-codelab נראה את המדד שתועד במסוף Firebase.
מטרת FirstDrawListener
בקטע שלמעלה רשמנו FirstDrawListener. המטרה של FirstDrawListener היא למדוד מתי הפריים הראשון התחיל ומתי הוא סיים את הציור.
הוא מיישם את ViewTreeObserver.OnDrawListener ומבטל את הקריאה החוזרת onDraw() שמופעלת כשעץ התצוגה עומד להימשך. לאחר מכן, המערכת עוטפת את התוצאה כדי לספק שני ק回调ים של כלי עזר: onDrawingStart() ו-onDrawingFinish().
הקוד המלא של FirstDrawListener מופיע בקוד המקור של ה-codelab הזה.
6. מדידת זמן הטעינה של Fragment
מדידת זמן הטעינה של Fragment דומה למדידה של זמן הטעינה של Activity, אבל יש כמה הבדלים קטנים. שוב, נגדיר מעקב אחר קוד בהתאמה אישית:
- עוקפים את
onAttach()callback ומתחילים להקליט אתfragmentLoadTrace. ניתן לטראס הזה את השםTest-Fragment-LoadTime.
כמו שהוסבר בשלב קודם, אפשר ליצור את אובייקט ה-Fragment בכל שלב, אבל הוא הופך לפעיל רק כשהוא מצורף ל-Activity המארח שלו.
TestFragment.java
public class TestFragment extends Fragment {
// TODO (1): Declare the Trace variable.
private Trace fragmentLoadTrace;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
// TODO (2): Start trace recording as soon as the Fragment is attached to its host Activity.
fragmentLoadTrace = FirebasePerformance.startTrace("TestFragment-LoadTime");
}
- רושמים את
FirstDrawListenerבקריאה החוזרתonViewCreated(). לאחר מכן, בדומה לדוגמה של הפעילות, מפסיקים את המעקב ב-onDrawingFinish().
TestFragment.java
@Override
public void onViewCreated(@NonNull View mainView, Bundle savedInstanceState) {
super.onViewCreated(mainView, savedInstanceState);
// ...
// TODO (3): Register the callback to listen for first frame rendering (see
// "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when view drawing is
// finished.
FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {
@Override
public void onDrawingStart() {
// In practice you can also record this event separately
}
@Override
public void onDrawingFinish() {
// This is when the Fragment UI is completely drawn on the screen
fragmentLoadTrace.stop();
}
});
- מריצים מחדש את האפליקציה. לאחר מכן מסננים את logcat באמצעות מדד מעקב אחר רישום ביומן. מקישים על הלחצן
LOAD FRAGMENTומחפשים יומנים כמו אלה שמופיעים בהמשך:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)
🎉 איזה כיף! מדדתם בהצלחה את זמן הטעינה של Fragment ודיווחתם על הנתונים האלה ל-מעקב אחר ביצועים ב-Firebase. בהמשך ה-codelab נראה את המדד שתועד במסוף Firebase.
7. הסבר על עיבוד המסך ומהי מסגרת איטית או פריים קפוא
רינדור של ממשק המשתמש הוא פעולה של יצירת פריים מהאפליקציה והצגתו על המסך. כדי לוודא שהאינטראקציה של המשתמש עם האפליקציה תהיה חלקה, האפליקציה צריכה לעבד פריימים בפחות מ-16 אלפיות השנייה כדי להגיע ל-60 פריימים לשנייה ( למה 60 פריימים לשנייה?). אם העיבוד של ממשק המשתמש באפליקציה איטי, המערכת נאלצת לדלג על פריימים, והמשתמש יחווה גמגום באפליקציה. אנחנו קוראים לזה גמגום.
באופן דומה, פריימים קפואים הם פריימים של ממשק המשתמש שזמן הרינדור שלהם ארוך מ-700 אלפיות השנייה. העיכוב הזה בעייתי כי נראה שהאפליקציה נתקעת ולא מגיבה לקלט של המשתמשים כמעט למשך שנייה שלמה בזמן שהפריים מוצג.
8. מדידת פריימים איטיים או קפואים של קטע
הכלי 'מעקב אחר ביצועים ב-Firebase' מתעד באופן אוטומטי פריימים איטיים או קפואים של פעילות (אבל רק אם היא מואצת על ידי חומרה). עם זאת, התכונה הזו לא זמינה כרגע ל-Fragments. הפריימים האיטיים או הקפואים של Fragment מוגדרים כפריימים האיטיים או הקפואים של כל הפעילות בין הקריאות החוזרות (callbacks) onFragmentAttached()ו-onFragmentDetached() במחזור החיים של ה-Fragment.
בהשראת המחלקה AppStateMonitor (שהיא חלק מ-Performance Monitoring SDK שאחראי על תיעוד של עקבות מסך לפעילות), הטמענו את המחלקה ScreenTrace (שהיא חלק ממאגר קוד המקור של ה-Codelab הזה). אפשר לקשר את המחלקה ScreenTrace לקריאה החוזרת במחזור חיים של FragmentManager הפעילות כדי לתעד פריימים איטיים או קפואים. המחלקה הזו מספקת שני ממשקי API ציבוריים:
-
recordScreenTrace(): מתחילים להקליט את המסך -
sendScreenTrace(): מפסיק את ההקלטה של מעקב אחר מסך ומצרף מדדים מותאמים אישית ליומן של ספירת המסגרות הכוללת, האיטית והקפואה
אם מצרפים את המדדים המותאמים אישית האלה, אפשר לטפל במעקב אחר מסכים של Fragments באותו אופן כמו במעקב אחר מסכים של Activity, ולהציג אותם יחד עם מעקב אחר עיבוד מסכים אחרים בלוח הבקרה Performance במסוף Firebase.
כך מתעדים את המסך עבור Fragment:
- מאתחלים את המחלקה
ScreenTraceבפעילות שמארחת את ה-Fragment.
MainActivity.java
// Declare the Fragment tag
private static final String FRAGMENT_TAG = TestFragment.class.getSimpleName();
// TODO (1): Declare the ScreenTrace variable.
private ScreenTrace screenTrace;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// TODO (2): Initialize the ScreenTrace variable.
screenTrace = new ScreenTrace(this, FRAGMENT_TAG);
// ...
}
- כשמטעינים את ה-Fragment, נרשמים ל-
FragmentLifecycleCallbacksומבטלים את ההגדרה של קריאות החזרהonFragmentAttached()ו-onFragmentDetached(). אנחנו עשינו את זה בשבילך. צריך להתחיל להקליט עקבות מסך בפונקציית הקריאה החוזרתonFragmentAttached()ולהפסיק את ההקלטה בפונקציית הקריאה החוזרתonFragmentDetached().
MainActivity.java
private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
super.onFragmentAttached(fm, f, context);
// TODO (3): Start recording the screen traces as soon as the Fragment is
// attached to its host Activity.
if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
screenTrace.recordScreenTrace();
}
}
@Override
public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {
super.onFragmentDetached(fm, f);
// TODO (4): Stop recording the screen traces as soon as the Fragment is
// detached from its host Activity.
if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
screenTrace.sendScreenTrace();
}
// Unregister Fragment lifecycle callbacks after the Fragment is detached
fm.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
}
};
- מפעילים מחדש את האפליקציה ולוחצים על הלחצן
LOAD FRAGMENT. מחכים כמה שניות ואז לוחצים עלback buttonבסרגל הניווט התחתון.
מסננים את ה-Logcat לפי מדד מעקב של רישום ביומן, ואז מחפשים יומנים כמו אלה שמוצגים בהמשך:
I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)
מסננים את logcat באמצעות FireperfViews, ואז מחפשים יומנים כמו אלה שבהמשך:
D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX
🎉 איזה כיף! הצלחתם למדוד את המסגרות האיטיות או הקפואות של מקטע (fragment) ולדווח על הנתונים האלה ל-מעקב אחר ביצועים ב-Firebase. בהמשך ה-codelab נראה את המדדים שתועדו במסוף Firebase.
9. בדיקת מדדים במסוף Firebase
- ב-logcat, לוחצים על כתובת ה-URL של מסוף Firebase כדי לעבור לדף הפרטים של מעקב.

אפשרות נוספת: במסוף Firebase, בוחרים את הפרויקט שכולל את האפליקציה. בחלונית הימנית, מאתרים את הקטע Release & Monitor (השקה ומעקב) ולוחצים על Performance (ביצועים).
- בכרטיסייה הראשית מרכז בקרה, גוללים למטה לטבלת העקבות ולוחצים על הכרטיסייה עקבות בהתאמה אישית. בטבלה הזו מוצגים עקבות של קוד מותאם אישית שהוספנו קודם, וגם עקבות מוכנים לשימוש, כמו עקבות של
_app_start. - מחפשים את שני קודי המעקב של הקוד המותאם אישית,
TestActivity-LoadTimeו-TestFragment-LoadTime. כדי לראות פרטים נוספים על הנתונים שנאספו, לוחצים על משך הזמן של אחד מהם.

- בדף הפרטים של מעקב הקוד המותאם אישית מוצג מידע על משך המעקב (כלומר, זמן הטעינה שנמדד).

- אפשר גם לראות את נתוני הביצועים של מעקב המסך בהתאמה אישית.
- חוזרים לכרטיסייה הראשית לוח בקרה, גוללים למטה לטבלת העקבות ולוחצים על הכרטיסייה Screen rendering (עיבוד המסך). בטבלה הזו מוצגים עקבות המסך המותאמים אישית שהוספנו קודם, וגם עקבות מסך מוכנים לשימוש, כמו עקבות
MainActivity. - מוצאים את מעקב המסך המותאם אישית,
MainActivity-TestFragment. לוחצים על שם העקבות כדי לראות את הנתונים הנצברים של רינדור איטי ופריים קפוא.

10. מזל טוב
כל הכבוד! הצלחתם למדוד את זמן הטעינה ואת ביצועי העיבוד של מסך של Activity ושל מקטע (fragment) באמצעות מעקב אחר ביצועים ב-Firebase.
מה השגתם
- שילבתם את מעקב אחר ביצועים ב-Firebase באפליקציה לדוגמה
- עכשיו אתם מבינים את מחזור החיים של טעינת התצוגה
- הוספתם עקבות של קוד בהתאמה אישית כדי למדוד את זמן הטעינה של Activity ושל Fragment
- הקלטתם פריימים איטיים או קפואים על ידי הוספה של מעקב מותאם אישית אחר מסכים עם מדדים מותאמים אישית
המאמרים הבאים
ב-Firebase Performance יש דרכים נוספות למדידת הביצועים של האפליקציה, מלבד מעקב מותאם אישית. הכלי מודד באופן אוטומטי נתוני ביצועים של זמן הפעלת האפליקציה, האפליקציה בחזית והאפליקציה ברקע. הגיע הזמן לבדוק את המדדים האלה במסוף Firebase.
בנוסף, Firebase Performance מציע מעקב אוטומטי אחר בקשות רשת HTTP/S. כך תוכלו להטמיע בקלות בקשות רשת בלי לכתוב שורת קוד אחת. אפשר לנסות לשלוח כמה בקשות לרשת מהאפליקציה ולחפש את המדדים במסוף Firebase?
בונוס
עכשיו כשאתה יודע איך למדוד את זמן הטעינה ואת ביצועי העיבוד של המסך של הפעילות או של מקטע (fragment) באמצעות מעקב אחר קוד מותאם אישית, האם תוכל לעיין בבסיס הקוד שלנו עם קוד פתוח כדי לראות אם אפשר לתעד את המדדים האלה מחוץ לקופסה עבור כל פעילות או מקטע (fragment) שמהווים חלק מהאפליקציה? אפשר לשלוח את ה-PR אם רוצים :-)
11. למידה נוספת
הבנה של מה שקורה במהלך הטעינה של פעילות תעזור לכם להבין טוב יותר את מאפייני הביצועים של האפליקציה. בשלב מוקדם יותר, תיארנו ברמה גבוהה מה קורה במהלך הטעינה של פעילות, אבל ב<term ref="diagram">דיאגרמה</term> הבאה מתואר כל שלב בפירוט רב יותר.
