使用 Firebase 效能監控測量載入時間和螢幕渲染

一、簡介

最後更新: 2021-03-11

為什麼我們需要衡量Views的效能?

視圖是Android應用程式的關鍵部分,直接影響使用者體驗。例如,您的 Activity 或 Fragment 包含 UI,其中包含使用者與之互動的 View 元件。在 UI 完全繪製在螢幕上之前,使用者無法看到 UI 的全部內容。緩慢和凍結的螢幕將直接損害用戶與應用程式的交互,並造成糟糕的用戶體驗。

Firebase 效能監控是否不提供這些開箱即用的效能指標?

Firebase 效能監控會自動擷取一些開箱即用的效能數據,例如您的應用程式啟動時間(即僅第一個Activity 的載入時間)和螢幕渲染效能(即 Activity 的緩慢和凍結幀,但不是碎片) 。然而,產業應用通常沒有很多Activity,而是一個Activity和多個Fragment。此外,許多應用程式通常會為更複雜的用例實作自己的自訂視圖。因此,了解如何透過在應用程式中偵測自訂程式碼追蹤來測量「活動」和「片段」的載入時間和螢幕渲染效能通常很有用。您可以輕鬆擴展此 Codelab 以測量自訂視圖元件的效能。

你將學到什麼

  • 如何將 Firebase 效能監控新增至 Android 應用
  • 了解 Activity 或 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插件向 Firebase 專案註冊我們的 Android 應用,並向我們的 Android 專案添加必要的 Firebase 設定檔、插件和依賴項 -所有這些都在 Android Studio 中進行

將您的應用程式連接到 Firebase

  1. 前往Android Studio /說明>檢查更新,確保您使用的是最新版本的 Android Studio 和 Firebase Assistant。
  2. 選擇“工具” > “Firebase”以開啟“助手”窗格。

e791bed0999db1e0.png

  1. 選擇要新增到您的應用程式的效能監控,然後按一下效能監控入門
  2. 按一下「連線至 Firebase」以將您的 Android 專案與 Firebase 連線(這將在瀏覽器中開啟 Firebase 控制台)
  3. 在 Firebase 控制台中,點選新增項目,然後輸入 Firebase 項目名稱(如果您已有 Firebase 項目,則可以選擇該現​​有項目) 。按一下繼續並接受條款以建立 Firebase 專案和新的 Firebase 應用程式。
  4. 接下來您應該會看到一個對話框,用於將新的 Firebase 應用程式連接到您的 Android Studio 專案。

42c498d28ead2b77.png

  1. 返回 Android Studio,在Assistant窗格中,您應該會看到您的應用程式已連接到 Firebase 的確認資訊。

dda8bdd9488167a0.png

將效能監控新增至您的應用程式

在 Android Studio 的「助手」窗格中,按一下「將效能監控新增至您的應用程式」

您應該會看到一個接受更改的對話框,之後 Android Studio 應該會同步您的應用程式以確保已添加所有必要的依賴項。

9b58145acc4be030.png

最後,您應該在 Android Studio 的「助手」窗格中看到成功訊息,表示所有依賴項已正確設定。

aa0d46fc944e0c0b.png

作為附加步驟,請依照「(選用)啟用偵錯日誌記錄」步驟中的說明啟用偵錯日誌記錄。公共文檔中也提供了相同的說明。

3.運行應用程式

如果您已成功將應用程式與效能監控 SDK 集成,則該專案現在應該可以編譯。在 Android Studio 中,按一下執行>運行「應用程式」以在連接的 Android 裝置/模擬器上建置並執行應用程式。

該應用程式有兩個按鈕,可將您帶到相應的 Activity 和 Fragment,如下所示:

410d8686b4f45c33.png

在此 Codelab 的以下步驟中,您將了解如何測量 Activity 或 Fragment 的載入時間和螢幕渲染效能。

4. 理解Activity或Fragment的載入

在這一步驟中,我們將了解系統在載入 Activity 或 Fragment 期間正在做什麼。

了解 Activity 的加載

對於 Activity,載入時間定義為從 Activity 物件建立一直到第一幀完全繪製在螢幕上的時間(這是使用者第一次看到 Activity 的完整 UI 的時間)時間)。要測量您的應用程式是否已完全繪製,您可以使用reportFullyDrawn()方法來測量應用程式啟動和完全顯示所有資源和視圖層次結構之間所經過的時間。

從較高的層面來看,當您的應用程式呼叫startActivity(Intent)時,系統會自動執行下列程序。每個過程都需要時間才能完成,這會增加建立 Activity 和使用者在螢幕上看到該 Activity 的 UI 之間的持續時間。

c20d14b151549937.png

了解 Fragment 的載入

與 Activity 類似,Fragment 的載入時間定義為從 Fragment 附加到其宿主 Activity 開始一直到 Fragment View 的第一幀完全繪製在螢幕上的時間。

5. 測量Activity的載入時間

第一幀的延遲可能會導致糟糕的使用者體驗,因此了解使用者所經歷的初始載入延遲程度非常重要。您可以偵測自訂程式碼追蹤來測量此載入時間:

  1. 建立 Activity 物件後,立即在 Activity 類別中啟動自訂程式碼追蹤(名為TestActivity-LoadTime )。

測試活動.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

測試活動.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)

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

FirstDrawListener 的用途

在上面的部分中,我們註冊了一個FirstDrawListenerFirstDrawListener的目的是測量第一幀何時開始並完成繪製。

它實作ViewTreeObserver.OnDrawListener並覆寫即將繪製視圖樹時呼叫的onDraw()回呼。然後它包裝結果以提供兩個實用程式回調onDrawingStart()onDrawingFinish()

FirstDrawListener的完整程式碼可以在此Codelab 的原始程式碼中找到。

6. 測量Fragment的載入時間

測量 Fragment 的載入時間與我們測量 Activity 的載入時間類似,但有一些細微的差別。同樣,我們將檢測自訂程式碼追蹤

  1. 覆蓋onAttach()回呼並開始記錄fragmentLoadTrace 。我們將此追蹤命名Test-Fragment-LoadTime

如同前面步驟所解釋的,Fragment 物件可以隨時創建,但只有當它附加到其宿主 Activity 時,它才會變成活動狀態。

測試片段.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()中停止追蹤。

測試片段.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 效能監控。我們稍後將在此 Codelab 中的 Firebase 控制台中查看記錄的指標。

7. 了解螢幕渲染以及什麼是慢幀/凍結幀

UI 渲染是從應用程式產生框架並將其顯示在螢幕上的行為。為了確保使用者與應用程式的交互順暢,您的應用程式應在 16 毫秒內渲染幀,以達到每秒 60 幀(為什麼是 60 fps? )。如果您的應用程式的 UI 渲染速度較慢,則係統將被迫跳幀,並且使用者會感覺到您的應用程式出現卡頓現象。我們稱之為卡頓

同樣,凍結幀是渲染時間超過 700 毫秒的 UI 幀。這種延遲是一個問題,因為您的應用程式似乎被卡住了,並且在幀渲染時幾乎一整秒鐘都沒有響應用戶輸入。

8. 測量片段的慢速/凍結幀

Firebase 效能監控會自動擷取活動的慢速/凍結幀(但前提是該活動是硬體加速的)。但是,此功能目前不適用於 Fragment。 Fragment 的慢/凍結幀定義為 Fragment 生命週期中onFragmentAttached()onFragmentDetached()回呼之間整個 Activity 的慢/凍結幀。

受到AppStateMonitor類別(它是效能監控 SDK 的一部分,負責記錄 Activity 的螢幕追蹤)的啟發,我們實現了ScreenTrace類別(它是此 Codelab 原始程式碼儲存庫的一部分)。 ScreenTrace類別可以連接到 Activity 的FragmentManager的生命週期回呼來捕捉緩慢/凍結的幀。這個類別提供了兩個公共API:

  • recordScreenTrace() :開始記錄螢幕軌跡
  • sendScreenTrace() :停止螢幕追蹤記錄並附加自訂指標來記錄總幀數、慢幀數和凍結幀數

透過附加這些自訂指標,片段的螢幕追蹤可以與活動的螢幕追蹤相同的方式處理,並且可以與其他螢幕渲染追蹤一起顯示在 Firebase 控制台的效能儀表板中。

以下是記錄 Fragment 的螢幕追蹤的方法:

  1. 在託管 Fragment 的 Activity 中初始化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

使用「 Logging Trace metric 」篩選 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 效能監控。我們稍後將在本 Codelab 中查看 Firebase 控制台中記錄的指標。

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

  1. 在 logcat 中,按一下 Firebase 控制台 URL 以存取追蹤的詳細資訊頁面。 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 Console中檢查這些指標了。

此外,Firebase Performance 還提供自動 HTTP/S 網路請求監控。這樣您就可以輕鬆地偵測網路請求,而無需編寫任何程式碼。您可以嘗試從您的應用程式發送一些網路請求並在Firebase 控制台中尋找指標嗎?

獎金

現在您已經知道如何使用自訂程式碼追蹤來測量 Activity/Fragment 的載入時間和螢幕渲染效能,您可以探索我們的開源程式碼庫,看看是否可以擷取任何 Activity/Fragment 的開箱即用的這些指標這是應用程式的一部分?如果您願意,請隨時發送 PR :-)

11. 獎勵學習

了解 Activity 載入過程中發生的情況將幫助您更好地了解應用程式的效能特徵。在前面的步驟中,我們概括地描述了 Activity 載入過程中發生的情況,但下圖更詳細地描述了每個階段。

cd61c1495fad7961.png