使用 Firebase Performance Monitoring 評估載入時間和畫面算繪情形

1. 簡介

上次更新時間:2021 年 3 月 11 日

為什麼必須評估觀看次數成效?

檢視畫面是 Android 應用程式中直接影響使用者體驗的重要部分。舉例來說,「活動」或「片段」包含的 UI,會保留使用者與其互動的 View 元件。使用者無法查看 UI 的完整內容,直到 UI 內容完全繪製在螢幕上。緩慢和凍結畫面會直接影響使用者與應用程式的互動,並造成不良的使用者體驗。

Firebase Performance Monitoring 不會立即提供這些成效指標嗎?

Firebase 效能監控功能會自動擷取部分立即運作的效能資料,例如應用程式的啟動時間 (僅限「第一個」活動的載入時間) 和畫面轉譯效能 (例如「活動」的緩慢和凍結影格,但「片段」則不適用)。不過,業界應用程式通常沒有大量活動,而是只有一個活動和多個片段。此外,許多應用程式通常會實作自訂檢視區塊,以因應更複雜的用途。因此,瞭解如何在應用程式中檢測自訂程式碼追蹤記錄,以評估活動和片段的載入時間和畫面轉譯效能,總會很有幫助。您可以輕鬆擴充本程式碼研究室,評估自訂檢視區塊元件的效能。

課程內容

  • 如何將 Firebase Performance Monitoring 新增至 Android 應用程式
  • 瞭解活動或片段的載入方式
  • 如何檢測自訂程式碼追蹤記錄以評估活動或片段的載入時間
  • 瞭解螢幕轉譯作業和緩慢/凍結影格是什麼
  • 如何檢測自訂程式碼追蹤記錄和指標,以記錄緩慢/凍結畫面
  • 如何在 Firebase 控制台中查看收集到的指標

軟硬體需求

  • Android Studio 4.0 以上版本
  • Android 裝置/模擬器
  • Java 8 以上版本

2. 開始設定

取得程式碼

執行下列指令,複製本程式碼研究室的程式碼範例。這項操作會在您的電腦上建立名為 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 檔案而收到警告訊息。我們會在這個步驟的下一節修正這個問題。

在本程式碼研究室中,我們會使用 Firebase Assistant 外掛程式,向 Firebase 專案註冊 Android 應用程式,並將必要的 Firebase 設定檔、外掛程式和依附元件加入 Android 專案 — 只需在 Android Studio 中就能完成!

將應用程式連結至 Firebase

  1. 前往「Android Studio」/「Help」(說明) >請檢查更新,確保您使用的是最新版的 Android Studio 和 Firebase Assistant。
  2. 選取「工具」>Firebase,開啟「Assistant」窗格。

e791bed0999db1e0.png

  1. 選擇「Performance Monitoring」新增到應用程式,然後按一下「開始使用 Performance Monitoring」
  2. 按一下「連結至 Firebase」,將 Android 專案連結至 Firebase (這會在瀏覽器中開啟 Firebase 控制台)
  3. 在 Firebase 控制台中按一下「新增專案」,然後輸入 Firebase 專案名稱(如果您已有 Firebase 專案,可以改為選取該現有專案)。按一下「繼續」並接受條款,以建立 Firebase 專案和新的 Firebase 應用程式。
  4. 接著您應該會看到一個對話方塊,將新的 Firebase 應用程式連結至 Android Studio 專案。

42c498d28ead2b77.png

  1. 返回 Android Studio 的「Assistant」窗格,您應該會看到確認應用程式已連線至 Firebase。

dda8bdd9488167a0.png

在應用程式中新增 Performance Monitoring

在 Android Studio 的「Assistant」窗格中,按一下「Add Performance Monitoring to app」

系統應會顯示「Accept Changes」對話方塊,然後 Android Studio 應同步處理應用程式,以確保已新增所有必要的依附元件。

9b58145acc4be030.png

最後,Android Studio 的「Assistant」窗格應會顯示成功訊息,指出所有依附元件皆已正確設定。

aa0d46fc944e0c0b.png

另外,請按照「(選用) 啟用偵錯記錄功能」步驟中的操作說明啟用偵錯記錄功能公開說明文件也提供相同的操作說明。

3. 執行應用程式

如果您已成功將應用程式與 Performance Monitoring SDK 整合,現在應該就能編譯專案。在 Android Studio 中,按一下「Run」(執行) >執行「應用程式」,在已連結的 Android 裝置/模擬器上建構及執行應用程式。

應用程式有兩個按鈕,可將您導向對應的 Activity 和 Fragment,如下所示:

410d8686b4f45c33.png

在本程式碼研究室的後續步驟中,您將瞭解如何評估活動或片段的載入時間和畫面轉譯效能。

4. 瞭解活動或片段的載入方式

在這個步驟中,我們會瞭解系統在載入活動或片段時正在執行什麼作業。

瞭解活動載入

對活動而言,載入時間是指從活動物件建立到一直到畫面呈現第一個畫面為止 (也就是使用者首次看到活動的完整 UI 時) 開始的時間。如要評估應用程式是否已完整繪製,可以使用 reportFullyDrawn() 方法測量應用程式啟動之間經過的時間,以及完成所有資源和檢視區塊階層的顯示時間。

大致來說,當應用程式呼叫 startActivity(Intent) 時,系統會自動執行下列程序。每個程序皆需要時間才能完成,因此加上從活動建立到使用者在畫面上看到活動 UI 的間隔時間。

c20d14b151549937.png

瞭解 Fragment 的載入方式

片段的載入時間與 Fragment 的載入時間類似,定義是從 Fragment 附加至代管活動時起算,直到 Fragment View 的第一個影格為止繪製在畫面上為止。

5. 測量活動的載入時間

第一個影格發生延遲可能會導致使用者體驗不佳,因此請務必瞭解使用者在初始載入時花費多少時間。您可以檢測自訂程式碼追蹤記錄以測量這項載入時間:

  1. 建立 Activity 物件後,立即在 Activity 類別中啟動自訂程式碼追蹤記錄 (名為 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");

    // ...

}
  1. 覆寫 onCreate() 回呼,並取得 setContentView() 方法加入的 View。
@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);     

    // ...
}
  1. 我們已加入 FistDrawListener 實作,其中包含兩個回呼:onDrawingStart()onDrawingFinish() (如要進一步瞭解FirstDrawListener 以及可能影響其效能的因素,請參閱下一節)。在 Activity 的 onCreate() 回呼結尾註冊 FirstDrawListener。您應在 onDrawingFinish() 回呼中停止 viewLoadTrace

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();             
        }         
    });
  1. 重新執行應用程式。然後使用「Logging 追蹤指標」篩選 logcat。輕觸 LOAD ACTIVITY 按鈕,然後查看類似下方的記錄:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉? 恭喜!您已成功評估活動的載入時間,並將相關資料回報至 Firebase Performance Monitoring。本程式碼研究室稍後會在 Firebase 控制台中查看記錄指標。

FirstDrawListener 的用途

在上面的部分中,我們註冊了 FirstDrawListenerFirstDrawListener 的用途是測量第一個影格開始和結束繪圖的時間。

這個函式會實作 ViewTreeObserver.OnDrawListener 並覆寫 onDraw() 回呼,以在 View 樹狀結構即將繪製時叫用。接著會包裝結果,提供兩個公用程式回呼 onDrawingStart()onDrawingFinish()

您可以在這個程式碼研究室的原始碼中找到 FirstDrawListener 的完整程式碼。

6. 測量片段的載入時間

Fragment 的載入時間的測量方式,與我們為 Activity 測量時類似,但有些微差異。同樣地,我們會檢測自訂程式碼追蹤記錄

  1. 覆寫 onAttach() 回呼,並開始記錄 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");
   }
  1. onViewCreated() 回呼中註冊 FirstDrawListener。接著,與 Activity 範例類似,請停止 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();
       }
   });
  1. 重新執行應用程式。然後使用「Logging 追蹤指標」篩選 logcat。輕觸 LOAD FRAGMENT 按鈕,然後查看類似下方的記錄:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉? 恭喜!您已成功評估片段的載入時間,並將相關資料回報至 Firebase Performance Monitoring。本程式碼研究室稍後會在 Firebase 控制台中查看記錄指標。

7. 瞭解螢幕轉譯作業和緩慢/凍結影格是什麼

UI 轉譯是指從應用程式產生並在螢幕中顯示影格的動作。為了確保使用者與應用程式的互動順暢,應用程式的影格轉譯速度應在 16 毫秒以內,才能達到每秒 60 個影格 ( 為什麼是 60fps?)。如果應用程式的 UI 顯示速度緩慢,系統會強制略過影格,使用者就會感覺到應用程式有延遲現象。我們稱之為「卡頓」

同樣地,凍結影格是指轉譯時間超過 700 毫秒的 UI 影格。這段延遲會造成問題,因為應用程式在顯示時似乎停滯不動,且在影格轉譯時幾乎有整整一秒沒有回應使用者輸入內容。

8. 評估片段的緩慢/凍結影格

Firebase Performance Monitoring 會自動擷取活動速度緩慢/凍結的影格 (僅限硬體加速)。不過,Fragment 目前無法使用這項功能。Fragment 的緩慢/凍結影格是指在 Fragment 生命週期中,整個活動在 onFragmentAttached()onFragmentDetached() 回呼之間的緩慢/凍結影格。

我們採取 AppStateMonitor 類別 (負責記錄「活動」螢幕追蹤記錄的 Performance Monitoring SDK 的一部分) 做為動機,而導入 ScreenTrace 類別 (這是本程式碼研究室原始碼存放區的一部分)。ScreenTrace 類別可連結至活動的 FragmentManager 生命週期回呼,以擷取緩慢/凍結影格。這個類別提供兩個公用 API:

  • recordScreenTrace():開始錄製螢幕追蹤記錄
  • sendScreenTrace():停止錄製螢幕畫面追蹤記錄,並附加自訂指標,記錄總影格數、緩慢影格和凍結影格數

附加這些自訂指標後,Fragment 的螢幕追蹤記錄處理方式和「活動」的畫面追蹤記錄相同,而且可以連同其他畫面轉譯追蹤記錄一起顯示在 Firebase 控制台的「效能」資訊主頁中。

以下說明如何為 Fragment 記錄畫面追蹤記錄:

  1. 在代管片段的活動中初始化 ScreenTrace 類別。

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);

    // ...
}
  1. 載入 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);
           }
       };
  1. 重新執行應用程式。然後輕觸「LOAD FRAGMENT」按鈕。等待幾秒鐘,然後按一下底部導覽列的 back button

使用「記錄追蹤記錄指標」篩選 logcat,然後尋找類似下方的記錄:

I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)

使用「FireperfViews」篩選 logcat,再查看下列記錄:

D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX

🎉? 恭喜!您已成功評估片段的緩慢/凍結影格,並將相關資料回報至 Firebase Performance Monitoring。稍後在這個程式碼研究室中,我們會到 Firebase 控制台查看記錄的指標。

9. 在 Firebase 控制台中查看指標

  1. 在 logcat 中,按一下 Firebase 主控台網址,前往追蹤記錄的詳細資料頁面。ceb9d5ba51bb6e89.jpeg

您也可以在 Firebase 控制台,選取含有您應用程式的專案。在左側面板中,找到「發布與」監控部分,然後按一下「效能」

  • 在主要「資訊主頁」分頁中,向下捲動至追蹤記錄表格,然後按一下「自訂追蹤記錄」分頁標籤。在這個表格中,您會看到我們稍早新增的自訂程式碼追蹤記錄,以及一些立即可用的追蹤記錄,例如 _app_start 追蹤記錄。
  • 找出 TestActivity-LoadTimeTestFragment-LoadTime 這兩個自訂程式碼追蹤記錄。按一下任一項的「時間長度」,即可查看收集資料的更多詳情。

a0d8455c5269a590.png

  1. 自訂程式碼追蹤記錄的詳細資料頁面會顯示追蹤記錄時間長度 (也就是測量的載入時間) 的資訊。

5e92a307b7410d8b.png

  1. 您也可以查看自訂畫面追蹤記錄的效能資料。
  • 返回「資訊主頁」主分頁,向下捲動至追蹤記錄表格,然後按一下「畫面轉譯」分頁標籤。在這個表格中,您會看到我們稍早新增的自訂畫面追蹤記錄,以及任何立即可用的螢幕追蹤記錄 (例如 MainActivity 追蹤記錄)。
  • 找出自訂畫面追蹤記錄 MainActivity-TestFragment,按一下追蹤記錄名稱,即可查看轉譯速度緩慢和凍結影格的匯總資料。

ee7890c7e2c28740.png

10. 恭喜

恭喜!您已成功使用 Firebase Performance Monitoring,評估活動和片段的載入時間和畫面轉譯效能!

您的成就

後續步驟

除了自訂追蹤記錄以外,Firebase 效能還提供更多評估應用程式效能的方式。系統會自動測量應用程式啟動時間、前景應用程式,以及應用程式在背景運作的效能資料。屆時您可以在 Firebase 控制台查看這些指標。

此外,Firebase Performance 也提供自動 HTTP/S 網路要求監控功能。透過這個工具,您無須編寫任何程式碼即可輕鬆檢測網路要求。請先嘗試透過應用程式傳送網路要求,並在 Firebase 控制台中尋找指標嗎?

獎勵

現在您已經瞭解如何利用自訂程式碼追蹤記錄,評估活動/片段的載入時間和畫面轉譯效能,不妨看看我們的開放原始碼程式碼集,看看能否從應用程式的任何活動/片段中直接擷取這些指標?如有需要,歡迎直接傳送 :-)

11. 額外學習

瞭解載入活動期間會發生的情況,可協助您進一步瞭解應用程式的效能特性。在前一步驟中,我們大致說明瞭載入活動期間會發生的情況,但下圖更詳細地說明每個階段。

cd61c1495fad7961.png