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

1. 簡介

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

為什麼需要評估觀看次數的成效?

檢視區塊是 Android 應用程式的重要部分,直接影響使用者體驗。舉例來說,您的 Activity 或 Fragment 包含 UI,其中含有使用者互動的 View 元件。使用者必須等到 UI 完全繪製在畫面上,才能看到完整內容。畫面緩慢或凍結會直接影響使用者與應用程式的互動,導致使用者體驗不佳。

Firebase Performance Monitoring 不是會提供這些現成的效能指標嗎?

Firebase Performance Monitoring 會自動擷取部分效能資料,例如應用程式啟動時間 (即第一個活動的載入時間) 和畫面算繪效能 (即活動的緩慢和凍結影格,而非片段)。不過,產業應用程式通常不會有許多活動,而是一個活動和多個片段。此外,許多應用程式通常會針對更複雜的使用情境實作自己的自訂檢視區塊。因此,在應用程式中操作自訂程式碼追蹤記錄,瞭解如何評估 Activity 和 Fragment 的載入時間和畫面算繪效能,通常很有幫助。您可以輕鬆擴充這個程式碼研究室,評估自訂檢視區塊元件的效能。

課程內容

  • 如何將 Firebase Performance Monitoring 新增至 Android 應用程式
  • 瞭解如何載入 Activity 或 Fragment
  • 如何操作自訂程式碼追蹤記錄,以評估活動或片段的載入時間
  • 瞭解畫面算繪,以及緩慢/凍結影格的定義
  • 如何使用指標檢測自訂程式碼追蹤記錄,以記錄緩慢/凍結的畫面
  • 如何在 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 應用程式,並在 Android 專案中新增必要的 Firebase 設定檔、外掛程式和依附元件,所有操作都能在 Android Studio 中完成

將應用程式連結至 Firebase

  1. 依序前往「Android Studio」/「Help」>「Check for updates」,確認您使用的是最新版本的 Android Studio 和 Firebase Assistant。
  2. 依序選取「Tools」 >「Firebase」,開啟「Assistant」窗格。
    e791bed0999db1e0.png
  3. 選擇要新增至應用程式的「Performance Monitoring」,然後按一下「開始使用 Performance Monitoring」
  4. 按一下按鈕建立新專案,然後輸入專案名稱 (例如 Measure Performance Codelab)。
  5. 按一下「繼續」
  6. 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」
  7. (選用) 在 Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」)。
  8. 本程式碼研究室不需要 Google Analytics,因此請關閉 Google Analytics 選項。
  9. 接著,您應該會看到一個對話方塊,要求您將新的 Firebase 應用程式連結至 Android Studio 專案。
    42c498d28ead2b77.png
  10. 返回 Android Studio,在「Assistant」窗格中,您應該會看到應用程式已連結至 Firebase 的確認訊息。
    dda8bdd9488167a0.png

在應用程式中新增 Performance Monitoring

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

您應該會看到「接受變更」對話方塊,之後 Android Studio 應會同步處理應用程式,確保已新增所有必要依附元件。

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

此外,請按照「(選用) 啟用偵錯記錄」步驟中的操作說明,啟用偵錯記錄。您也可以在公開說明文件中找到相同操作說明。

3. 執行應用程式

如果應用程式已成功整合 Performance Monitoring SDK,專案現在應該會編譯。在 Android Studio 中,依序按一下「Run」>「Run ‘app'」,即可在已連線的 Android 裝置/模擬器上建構及執行應用程式。

應用程式有兩個按鈕,可帶您前往對應的活動和片段,如下所示:

410d8686b4f45c33.png

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

4. 瞭解如何載入 Activity 或 Fragment

在這個步驟中,我們將瞭解系統在載入活動或片段時執行的動作。

瞭解 Activity 的載入情形

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

整體來說,當應用程式呼叫 startActivity(Intent) 時,系統會自動執行下列程序。每個程序都需要時間才能完成,因此從建立 Activity 到使用者在畫面上看到 Activity 的 UI,這段時間會更長。

c20d14b151549937.png

瞭解片段的載入情形

與活動類似,片段的載入時間是指從片段附加至代管活動開始,到片段檢視區塊的第一個影格完全繪製在畫面上為止的時間。

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 trace metric」篩選 logcat。輕觸 LOAD ACTIVITY 按鈕,然後尋找類似下方的記錄:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 恭喜!您已成功測量 Activity 的載入時間,並將該資料回報給 Firebase Performance Monitoring。稍後,我們會在 Firebase 控制台中查看記錄的指標。

FirstDrawListener 的用途

在上一節中,我們註冊了 FirstDrawListenerFirstDrawListener 的用途是測量第一個影格開始和完成繪製的時間。

這個類別會實作 ViewTreeObserver.OnDrawListener,並覆寫 onDraw() 回呼,系統會在即將繪製檢視區塊樹狀結構時叫用此回呼。然後包裝結果,提供兩個實用回呼 onDrawingStart()onDrawingFinish()

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

6. 測量 Fragment 的載入時間

評估片段的載入時間與評估活動的載入時間類似,但有些微差異。我們將再次檢測自訂程式碼追蹤記錄

  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。然後,與「活動」範例類似,在 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 trace metric」篩選 logcat。輕觸 LOAD FRAGMENT 按鈕,然後尋找類似下方的記錄:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 恭喜!您已成功測量 Fragment 的載入時間,並將該資料回報給 Firebase 效能監控。稍後,我們會在 Firebase 控制台中查看記錄的指標。

7. 瞭解畫面轉譯和緩慢/凍結影格

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

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

8. 測量 Fragment 的緩慢/凍結影格

Firebase Performance Monitoring 會自動擷取 Activity 的緩慢/凍結影格 (但僅限於硬體加速)。不過,這項功能目前不適用於片段。片段的緩慢/凍結影格定義為片段生命週期中,onFragmentAttached()onFragmentDetached() 回呼之間整個活動的緩慢/凍結影格。

我們參考 AppStateMonitor 類別 (這是 Performance Monitoring SDK 的一部分,負責記錄 Activity 的畫面追蹤記錄),實作了 ScreenTrace 類別 (這是本程式碼研究室來源程式碼存放區的一部分)。ScreenTrace 類別可以連結至 Activity 的 FragmentManager 生命週期回呼,以擷取緩慢/凍結的影格。這個類別提供兩項公開 API:

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

附加這些自訂指標後,系統就能以處理 Activity 螢幕追蹤的方式處理 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

🎉 恭喜!您已成功測量 Fragment 的緩慢/凍結影格,並將該資料回報給 Firebase 效能監控。稍後,我們會在 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 效能監控,測量 Activity 和 Fragment 的載入時間和畫面算繪效能!

您達成的成就

後續步驟

除了自訂追蹤記錄,Firebase Performance 還提供更多應用程式效能評估方式。系統會自動測量應用程式啟動時間、應用程式在前台和背景的效能資料。現在請前往 Firebase 控制台查看這些指標。

此外,Firebase Performance 也提供自動 HTTP/S 網路要求監控功能。這樣一來,您就能輕鬆監控網路要求,完全不必編寫任何程式碼。請嘗試從應用程式傳送一些網路要求,並在 Firebase 控制台中尋找指標。

獎勵

您現在已瞭解如何使用自訂程式碼追蹤記錄,測量 Activity/Fragment 的載入時間和畫面算繪效能,接下來請探索我們的開放原始碼程式碼庫,看看是否能直接擷取應用程式中任何 Activity/Fragment 的這些指標。歡迎傳送 PR :-)

11. 額外學習內容

瞭解 Activity 載入期間發生的情況,有助於您進一步掌握應用程式的效能特徵。在先前的步驟中,我們已大致說明 Activity 載入期間發生的情況,但下圖會更詳細地說明每個階段。

cd61c1495fad7961.png