應用程式啟動分析與最佳化

使用者在應用程式啟動期間的體驗,會是他們對應用程式的第一印象。應用程式必須能迅速啟動並顯示使用者需要的資訊。如果啟動時間過長,使用者可能會因為等待太久而退出應用程式。

我們建議使用 Macrobenchmark 程式庫來測量啟動時間。這個程式庫可提供總覽和詳細的系統追蹤記錄,方便您掌握啟動期間發生的確切情況。

系統追蹤記錄會提供有關裝置動態的實用資訊,讓您瞭解應用程式在啟動期間做了哪些事、有哪些潛在改進方向。

如要分析應用程式啟動情況,請執行下列操作:

分析及改進應用程式啟動程序的步驟

一般來說,應用程式需要在啟動時載入對使用者至關重要的資源。非必要的資源可以等到啟動程序完成後再載入。

為了權衡效能,建議您考慮以下幾點:

  • 使用 Macrobenchmark 程式庫評估各項作業所需時間,找出需要較長時間才能完成的區塊。

  • 確認資源密集型作業對於應用程式啟動程序具有重要作用。如果該作業可以等到應用程式繪製完成再執行,即可將啟動時的資源限制降到最低。

  • 檢查該作業是否應在應用程式啟動時執行。舊程式碼或第三方程式庫常會呼叫不必要的作業。

  • 如果可行,請將長時間執行的作業移至背景。背景程序還是可能會影響啟動期間的 CPU 用量。

徹底調查作業後,就可以在所需載入時間與是否需要在應用程式啟動期間納入這項作業之間做出取捨。修改應用程式的工作流程時,請考量發生迴歸或破壞性變更的風險。

反覆改進與評估,直到您對應用程式的啟動時間感到滿意為止。如需更多資訊,請參閱「使用指標偵測及診斷問題」。

測量及分析主要作業耗費的時間

取得完整的應用程式啟動追蹤記錄後,請查看這份記錄並評估 bindApplicationactivityStart 等主要作業耗費的時間。我們建議使用 PerfettoAndroid Studio 分析器 來分析這些追蹤記錄。

請查看應用程式啟動花費的總時間,看看是否有符合下述情形的作業:

  • 需要較長時間、具有改進空間。每一毫秒都對效能至關重要。比如,請留意 Choreographer 繪製時間、版面配置加載時間、程式庫載入時間、Binder 交易,或資源載入時間 一般來說,請先檢查所有處理時間超過 20 毫秒的作業。
  • 封鎖主執行緒。詳情請參閱「瀏覽 Systrace 報表」。
  • 不需要在啟動期間執行。
  • 可以等第一個影格繪製後再執行。

請深入調查每筆追蹤記錄,找出效能有差距的地方。

找出主要執行緒上消耗大量資源的作業

最佳做法是從主執行緒中移除會耗用大量資源的作業,例如檔案 I/O 和網路存取作業。這在應用程式啟動期間也同樣重要,因為主執行緒上如有耗用大量資源的作業,會導致應用程式沒有回應,並延遲其他重要作業。您可以使用 StrictMode.ThreadPolicy,在主執行緒上找出消耗大量資源的作業。建議您對偵錯版本啟用 StrictMode,方便盡早找出問題,如以下範例所示:

Kotlin

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        ...
        if (BuildConfig.DEBUG)
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build()
            )
        ...
    }
}

Java

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ...
        if(BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(
                    new StrictMode.ThreadPolicy.Builder()
                            .detectAll()
                            .penaltyDeath()
                            .build()
            );
        }
        ...
    }
}

您可以使用 StrictMode.ThreadPolicy,在所有偵錯版本上啟用執行緒政策,並在偵測到違反執行緒政策情形時讓應用程式停止運作,這樣就不太會錯過這類情形。

TTID 和 TTFD

如要查看應用程式產生第一個影格所需的時間,請評估初始顯示時間 (TTID)。不過,這項指標不一定會反映使用者能開始與應用程式互動前的等候時間。因此,如果您希望應用程式狀態完整可用,就更適合使用完整顯示時間 (TTFD) 指標評估及改善必要的程式碼路徑。

如要瞭解應用程式 UI 繪製完成時的回報策略,請參閱「提高啟動時間準確度」。

請同時針對 TTID 和 TTFD 進行最佳化,因為兩者在各自的領域都至關重要。TTID 偏短時,有助於使用者瞭解應用程式正在確實啟動;而維持偏短的 TTFD,則是確保使用者能快速與應用程式互動的關鍵。

分析整體執行緒狀態

選取應用程式啟動時間,查看整體執行緒配量。主要執行緒必須隨時能夠回應。

Android Studio Profiler 等工具 Perfetto 提供主執行緒的詳細總覽,以及目前在容器中花費的時間 每個階段如要進一步瞭解如何以視覺化方式呈現 Perfetto 追蹤記錄,請參閱 Perfetto UI 說明文件。

找出主執行緒休眠狀態的關鍵區塊

如果應用程式長時間處於休眠狀態,可能是因為應用程式的主執行緒正在等待工作完成。對於多執行緒的應用程式,請找出主執行緒在等待的執行緒,並考慮改進相關作業。這也有助於確保關鍵路徑不會因為不必要的鎖定爭用而出現延遲。

減少讓主執行緒進入封鎖和不可中斷的休眠狀態

請找出每次主執行緒進入封鎖狀態的情況。Perfetto 和 Studio Profiler 的執行緒狀態時間軸會以橘色指標顯示這些情況。請辨識相關作業,檢查這些作業是否符合預期或可以避免,並視需要加以改進。

與 IO 相關的可中斷休眠可能是值得改進的地方。其他執行 IO 的程序 (甚至是無關的應用程式) 都能與頂端應用程式在執行的 IO 競爭。

縮短啟動時間

找出可以改進的空間後,請考慮採用下列解決方案來縮短啟動時間:

  • 延後並以非同步方式載入內容,縮短初始顯示時間
  • 盡量減少呼叫會發出 Binder 呼叫的函式。如果這類函式具有必要性,請務必改進相關呼叫,比如以快取值的方式取代重複呼叫,或是將非封鎖性工作移至背景執行緒。
  • 為了讓應用程式看起來更快啟動,可以盡快對使用者顯示需要最少轉譯作業的內容,讓他們不必空等畫面其餘部分載入。
  • 在應用程式中建立及新增啟動設定檔
  • 使用 Jetpack 應用程式啟動程式庫,簡化應用程式啟動期間的元件初始化作業。

分析 UI 效能

應用程式啟動程序包括啟動畫面和首頁載入時間。如要改進應用程式啟動程序,請查看追蹤記錄,瞭解繪製 UI 所需的時間。

限制初始化作業

某些影格的載入時間可能比較久。這類影格可視為在應用程式中具有較高的繪製成本。

如要改善初始化作業,請執行下列操作:

  • 優先處理並改進緩慢的版面配置階段。
  • 新增自訂追蹤記錄事件,方便調查來自 Perfetto 的每個警告以及 Systrace 發出的所有快訊,減少高成本的繪圖和延遲情形。

測量影格資料

測量影格資料的方法很多,以下是五種主要的資料收集方法:

  • 使用 dumpsys gfxinfo 在本機收集資料:在 dumpsys 資料中觀察到的影格不一定都會導致應用程式轉譯速度緩慢,或是對使用者造成任何影響。不過,觀察這項指標在不同發布週期之間的變化,有助於掌握整體的效能趨勢。想進一步瞭解如何使用 gfxinfoframestats 將 UI 效能測量結果整合至測試,請參閱「測試 Android 應用程式的基礎知識」。
  • 使用 JankStats 收集欄位資料:使用 JankStats 程式庫從應用程式的特定部分收集影格轉譯時間資料,並記錄及分析資料。
  • 在測試中使用 Macrobenchmark (後端有 Perfetto)
  • Perfetto FrameTimeline 在 Android 12 (API 級別 31) 中,您可以收集影格時間軸 指標 來自 Perfetto 追蹤記錄中,瞭解導致影格遺失的工作。如果想診斷影格遺失的原因,不妨從這裡著手。
  • 使用 Android Studio Profiler 偵測卡頓情形

查看主要活動載入時間

應用程式的主要活動可能包含從多個來源載入的大量資訊。請檢查首頁的 Activity 版面配置,特別是查看首頁活動的 Choreographer.onDraw 方法。

  • 使用 reportFullyDrawn 向系統回報,應用程式繪製作業已完全符合最佳化要求。
  • 使用 StartupTimingMetric 搭配 Macrobenchmark 程式庫來評估活動和應用程式啟動情形。
  • 查看影格遺失情形。
  • 找出轉譯或測量很耗時的版面配置。
  • 找出載入很耗時的素材資源。
  • 找出不需要在啟動期間加載的版面配置。

如要縮短主要活動的載入時間,請考慮以下可行的解決方案:

  • 在初始版面配置上,盡可能只顯示基本元素。詳情請參閱「最佳化版面配置階層」。
  • 新增自訂追蹤點,取得有關影格遺失和複雜版面配置的更多資訊。
  • 盡量減少啟動期間載入的點陣圖資源數量與大小。
  • 在版面配置非立即 VISIBLE 的地方使用 ViewStubViewStub 是大小為零的隱藏檢視區塊,可用於在執行階段延後加載版面配置資源。詳情請參閱 ViewStub 的說明。

    使用 Jetpack Compose 時,您可以使用狀態延遲載入部分元件,執行與 ViewStub 類似的行為:

    var shouldLoad by remember {mutableStateOf(false)}
    
    if (shouldLoad) {
     MyComposable()
    }
    

    修改 shouldLoad,在條件式區塊中載入可組合函式:

    LaunchedEffect(Unit) {
     shouldLoad = true
    }
    

    這會觸發重組,其中包含第一個程式碼片段中條件式區塊內的程式碼。

,瞭解如何調查及移除這項存取權。