使用 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