一、簡介
最後更新: 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
- 前往Android Studio /說明>檢查更新,確保您使用的是最新版本的 Android Studio 和 Firebase Assistant。
- 選擇“工具” > “Firebase”以開啟“助手”窗格。
- 選擇要新增到您的應用程式的效能監控,然後按一下效能監控入門。
- 按一下「連線至 Firebase」以將您的 Android 專案與 Firebase 連線(這將在瀏覽器中開啟 Firebase 控制台) 。
- 在 Firebase 控制台中,點選新增項目,然後輸入 Firebase 項目名稱(如果您已有 Firebase 項目,則可以選擇該現有項目) 。按一下繼續並接受條款以建立 Firebase 專案和新的 Firebase 應用程式。
- 接下來您應該會看到一個對話框,用於將新的 Firebase 應用程式連接到您的 Android Studio 專案。
- 返回 Android Studio,在Assistant窗格中,您應該會看到您的應用程式已連接到 Firebase 的確認資訊。
將效能監控新增至您的應用程式
在 Android Studio 的「助手」窗格中,按一下「將效能監控新增至您的應用程式」 。
您應該會看到一個接受更改的對話框,之後 Android Studio 應該會同步您的應用程式以確保已添加所有必要的依賴項。
最後,您應該在 Android Studio 的「助手」窗格中看到成功訊息,表示所有依賴項已正確設定。
作為附加步驟,請依照「(選用)啟用偵錯日誌記錄」步驟中的說明啟用偵錯日誌記錄。公共文檔中也提供了相同的說明。
3.運行應用程式
如果您已成功將應用程式與效能監控 SDK 集成,則該專案現在應該可以編譯。在 Android Studio 中,按一下執行>運行「應用程式」以在連接的 Android 裝置/模擬器上建置並執行應用程式。
該應用程式有兩個按鈕,可將您帶到相應的 Activity 和 Fragment,如下所示:
在此 Codelab 的以下步驟中,您將了解如何測量 Activity 或 Fragment 的載入時間和螢幕渲染效能。
4. 理解Activity或Fragment的載入
在這一步驟中,我們將了解系統在載入 Activity 或 Fragment 期間正在做什麼。
了解 Activity 的加載
對於 Activity,載入時間定義為從 Activity 物件建立一直到第一幀完全繪製在螢幕上的時間(這是使用者第一次看到 Activity 的完整 UI 的時間)時間)。要測量您的應用程式是否已完全繪製,您可以使用reportFullyDrawn()
方法來測量應用程式啟動和完全顯示所有資源和視圖層次結構之間所經過的時間。
從較高的層面來看,當您的應用程式呼叫startActivity(Intent)
時,系統會自動執行下列程序。每個過程都需要時間才能完成,這會增加建立 Activity 和使用者在螢幕上看到該 Activity 的 UI 之間的持續時間。
了解 Fragment 的載入
與 Activity 類似,Fragment 的載入時間定義為從 Fragment 附加到其宿主 Activity 開始一直到 Fragment View 的第一幀完全繪製在螢幕上的時間。
5. 測量Activity的載入時間
第一幀的延遲可能會導致糟糕的使用者體驗,因此了解使用者所經歷的初始載入延遲程度非常重要。您可以偵測自訂程式碼追蹤來測量此載入時間:
- 建立 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");
// ...
}
- 重寫
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);
// ...
}
- 我們已經包含了
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();
}
});
- 重新運行應用程式。然後,使用「 Logging Trace metric 」過濾 logcat。點選
LOAD ACTIVITY
按鈕,然後尋找以下日誌:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)
🎉恭喜!您已成功測量活動的載入時間並將該資料回報給 Firebase 效能監控。我們稍後將在此 Codelab 中的 Firebase 控制台中查看記錄的指標。
FirstDrawListener 的用途
在上面的部分中,我們註冊了一個FirstDrawListener
。 FirstDrawListener
的目的是測量第一幀何時開始並完成繪製。
它實作ViewTreeObserver.OnDrawListener
並覆寫即將繪製視圖樹時呼叫的onDraw()
回呼。然後它包裝結果以提供兩個實用程式回調onDrawingStart()
和onDrawingFinish()
。
FirstDrawListener
的完整程式碼可以在此Codelab 的原始程式碼中找到。
6. 測量Fragment的載入時間
測量 Fragment 的載入時間與我們測量 Activity 的載入時間類似,但有一些細微的差別。同樣,我們將檢測自訂程式碼追蹤:
- 覆蓋
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");
}
- 在
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();
}
});
- 重新運行應用程式。然後,使用「 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 的螢幕追蹤的方法:
- 在託管 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);
// ...
}
- 當您載入 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);
}
};
- 重新運行應用程式。然後,點擊
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 控制台中檢查指標
- 在 logcat 中,按一下 Firebase 控制台 URL 以存取追蹤的詳細資訊頁面。
或者,在Firebase 控制台中,選擇包含您的應用程式的項目。在左側面板中,找到「發布和監控」部分,然後按一下「效能」 。
- 在主儀表板標籤中,向下捲動至追蹤表,然後按一下自訂追蹤標籤。在此表中,您將看到我們之前添加的自訂程式碼追蹤以及一些現成的跟踪,例如
_app_start
跟踪。 - 找到兩個自訂程式碼追蹤:
TestActivity-LoadTime
和TestFragment-LoadTime
。點擊任一持續時間以查看有關所收集資料的更多詳細資訊。
- 自訂程式碼追蹤的詳細資訊頁面顯示有關追蹤持續時間的資訊(即測量的載入時間)。
- 您也可以查看自訂螢幕追蹤的效能數據。
- 返回主儀表板選項卡,向下捲動至追蹤表,然後按一下螢幕渲染標籤。在此表中,您將看到我們之前添加的自訂螢幕追蹤以及任何現成的螢幕跟踪,例如
MainActivity
追蹤。 - 找到您的自訂畫面追蹤
MainActivity-TestFragment
。按一下追蹤名稱以查看慢速渲染和凍結幀的聚合資料。
10.恭喜你
恭喜!您已使用 Firebase 效能監控成功測量了 Activity 和 Fragment 的載入時間和螢幕渲染效能!
你已經完成了什麼
- 您將 Firebase 效能監控整合到範例應用中
- 現在你已經了解View載入的生命週期了
- 您透過新增自訂程式碼追蹤來測量 Activity 和 Fragment 的載入時間
- 您透過新增具有自訂指標的自訂螢幕追蹤記錄了慢速/凍結幀
下一步是什麼
除了自訂追蹤之外,Firebase Performance 還提供了更多應用效能測量方法。它會自動測量應用程式啟動時間、應用程式在前台和應用程式在背景的效能數據。現在您可以在Firebase Console中檢查這些指標了。
此外,Firebase Performance 還提供自動 HTTP/S 網路請求監控。這樣您就可以輕鬆地偵測網路請求,而無需編寫任何程式碼。您可以嘗試從您的應用程式發送一些網路請求並在Firebase 控制台中尋找指標嗎?
獎金
現在您已經知道如何使用自訂程式碼追蹤來測量 Activity/Fragment 的載入時間和螢幕渲染效能,您可以探索我們的開源程式碼庫,看看是否可以擷取任何 Activity/Fragment 的開箱即用的這些指標這是應用程式的一部分?如果您願意,請隨時發送 PR :-)
11. 獎勵學習
了解 Activity 載入過程中發生的情況將幫助您更好地了解應用程式的效能特徵。在前面的步驟中,我們概括地描述了 Activity 載入過程中發生的情況,但下圖更詳細地描述了每個階段。