使用 Firebase 性能監控測量加載時間和屏幕渲染

一、簡介

最後更新: 2021-03-11

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

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

Firebase 性能監控不是開箱即用地提供這些性能指標嗎?

Firebase 性能監控會自動捕獲一些開箱即用的性能數據,例如您的應用程序啟動時間(即,僅您的第一個Activity 的加載時間)和屏幕渲染性能(即,Activity 的緩慢和凍結幀,但不是片段)。但是,行業應用程序通常不會有很多活動,而是一個活動和多個片段。此外,許多應用程序通常為更複雜的用例實現自己的自定義視圖。因此,了解如何通過檢測應用程序中的自定義代碼跟踪來測量活動和片段的加載時間和屏幕渲染性能通常很有用。您可以輕鬆擴展此 Codelab 以測量自定義視圖組件的性能。

你會學到什麼

  • 如何將 Firebase 性能監控添加到 Android 應用
  • 了解 Activity 或 Fragment 的加載
  • 如何檢測自定義代碼跟踪以測量 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插件將我們的 Android 應用程序註冊到 Firebase 項目,並將必要的 Firebase 配置文件、插件和依賴項添加到我們的 Android 項目中——所有這些都來自 Android Studio

將您的應用連接到 Firebase

  1. 轉到Android Studio /幫助>檢查更新以確保您使用的是最新版本的 Android Studio 和 Firebase 助手。
  2. 選擇工具> Firebase以打開助手窗格。

e791bed0999db1e0.png

  1. 選擇Performance Monitoring以添加到您的應用程序,然後單擊Get started with Performance Monitoring
  2. 單擊Connect to Firebase以將您的 Android 項目與 Firebase 連接(這將在您的瀏覽器中打開 Firebase 控制台)
  3. 在 Firebase 控制台中,點擊Add project ,然後輸入 Firebase 項目名稱(如果您已有 Firebase 項目,則可以選擇該現​​有項目) 。點擊繼續並接受條款以創建 Firebase 項目和新的 Firebase 應用。
  4. 接下來,您應該會看到一個對話框,將您的新 Firebase 應用程序連接到您的 Android Studio 項目。

42c498d28ead2b77.png

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

dda8bdd9488167a0.png

將性能監控添加到您的應用程序

在 Android Studio 的Assistant窗格中,單擊Add Performance Monitoring to your app

您應該會看到一個接受更改的對話框,之後 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

了解片段的加載

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

🎉 恭喜!您已成功測量 Activity 的加載時間並將該數據報告給 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 幀(為什麼是 60fps? )。如果您的應用遇到 UI 渲染緩慢的問題,那麼系統會被迫跳幀,用戶會在您的應用中感覺到卡頓。我們稱之為jank

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

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

Firebase 性能監控會自動捕獲 Activity 的慢速/凍結幀(但前提是它是硬件加速的)。但是,此功能目前不適用於 Fragments。 Fragment 的慢/凍結幀定義為在 Fragment 生命週期中onFragmentAttached()onFragmentDetached()回調之間的整個 Activity 的慢/凍結幀。

AppStateMonitor類(它是 Performance Monitoring SDK 的一部分,負責記錄 Activity 的屏幕跟踪)中汲取靈感,我們實現了ScreenTrace類(它是這個 codelab 源代碼 repo 的一部分)。 ScreenTrace類可以連接到 Activity 的FragmentManager的生命週期回調,以捕獲慢速/凍結幀。該類提供了兩個公共 API:

  • recordScreenTrace() : 開始記錄屏幕軌跡
  • sendScreenTrace() :停止記錄屏幕跟踪並將自定義指標附加到日誌總、慢速和凍結幀計數

通過附加這些自定義指標,可以像處理 Activity 的屏幕跟踪一樣處理 Fragment 的屏幕跟踪,並且可以在 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() onFragmentAttached()回調中停止記錄。

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 控制台中,選擇包含您的應用的項目。在左側面板中,找到Release & Monitor部分,然後單擊Performance

  • 在主儀表板選項卡中,向下滾動到跟踪表,然後單擊自定義跟踪選項卡。在此表中,您將看到我們之前添加的自定義代碼跟踪以及一些開箱即用的跟踪,例如_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