iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
Mobile Development

Android 性能戰爭:從 Profiler 開始的 30 天優化實錄系列 第 27

# Day 27:【自動化戰爭】建立性能基準 (Benchmark)

  • 分享至 

  • xImage
  •  

各位戰士,歡迎來到第二十七天的戰場。昨天,我們部署了 StrictMode 這位「憲兵」,在開發階段監督我們的行為,防止我們寫出違反主執行緒紀律的程式碼。

StrictMode 能抓到那些「非黑即白」的嚴重違規,但它無法回答一些更細微、卻同樣致命的問題:

  • 這次 UI 改版,是否讓我們的應用啟動速度慢了 50 毫秒?
  • 新增的這個功能,是否讓 RecyclerView 的滾動掉幀率增加了 5%?
  • 這些微小的性能衰退,日積月累,最終會讓我們的應用程式從「健步如飛」變成「步履蹣跚」。

為了防止這種「慢性病」,我們需要從「主觀感覺」走向「客觀數據」。我們需要一套標準化、自動化的「體能測驗」,來為我們的應用建立一個性能基準 (Baseline)。而 Jetpack 推出的 Macrobenchmark 函式庫,就是我們建造這座測驗場的官方工具。


什麼是 Macrobenchmark (宏基準測試)?

Jetpack 提供了兩種基準測試函式庫,我們必須先分清它們的作戰目標:

  • Microbenchmark (微基準):用於測量一小段程式碼的 CPU 性能。例如,測試一個排序演算法的執行速度。它在一個獨立的迴圈中反覆運行函式,與真實的應用程式環境無關。
  • Macrobenchmark (宏基準):用於測量真實的使用者互動場景下的應用程式性能。它會啟動你真實的應用程式,模擬使用者操作(如點擊、滾動),並收集整個流程的性能指標。

對於我們關心的應用啟動速度UI 流暢度Macrobenchmark 是我們需要使用的唯一指定武器。


建立你的「體能測驗場」—— Macrobenchmark 模組

與 Baseline Profile 產生器類似,Macrobenchmark 測試必須在一個獨立的 Gradle 模組中執行。

  1. 在 Android Studio 中,選擇 File > New > New Module
  2. 在左側範本中選擇 Benchmark
  3. 在 Benchmark 模組類型中,選擇 Macrobenchmark
  4. Target application 指向你的主應用程式模組(通常是 :app)。

Android Studio 會為你配置好一切,包括建立一個 com.android.test 類型的模組,並添加 androidx.benchmark:benchmark-macro-junit4 等必要依賴。

⚠️ 重要作戰前提
為了得到最真實、最穩定的性能數據,Macrobenchmark 測試必須

  1. 在一個真實的、已 Root 的 Android 設備上運行(或至少是 Userdebug build 的設備,模擬器也可以但真實設備更佳)。
  2. 測試的對象,必須是你的應用程式的 release 版本isMinifyEnabled = true, isDebuggable = false)。因為 Debug 版本包含了大量調試程式碼,其性能表現與使用者實際安裝的版本有天壤之別。

編寫你的「體能測驗」腳本

現在,讓我們來編寫兩個最核心的測驗項目:應用啟動速度列表滾動流暢度

// In your :benchmark module
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startupCold() = benchmarkRule.measureRepeated(
        packageName = "com.your.package.name", // 替換成你的應用包名
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD,
        setupBlock = {
            // 在每次測量前,確保應用處於完全關閉的狀態
            pressHome()
        }
    ) { // 這是 `measureBlock`,定義了要測量的操作
        startActivityAndWait()
    }
}

上面的程式碼建立了一個測量冷啟動的基準測試。measureRepeated 會自動為我們運行 5 次測試,殺死 App,再冷啟動,收集數據,最後給出結果。

現在,讓我們加入一個測量 RecyclerView 滾動性能的測試:

// In the same file, or a new one
import androidx.benchmark.macro.FrameTimingMetric
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Direction

@Test
fun scrollList() = benchmarkRule.measureRepeated(
    packageName = "com.your.package.name",
    metrics = listOf(FrameTimingMetric()), // 我們關心的是「幀時序」,即 Jank
    iterations = 5,
    setupBlock = {
        // 先啟動到包含 RecyclerView 的那個 Activity
        startActivityAndWait(Intent("..."))
    }
) { // measureBlock
    // 找到你的 RecyclerView
    val list = device.findObject(By.res("your_recycler_view_id"))
    // 設定邊界,讓 fling 動作更穩定
    list.setGestureMargin(device.displayWidth / 5)
    // 執行一次快速滑動 (fling)
    list.fling(Direction.DOWN)
}

判讀「體測報告」

像運行普通儀器測試一樣,點擊函式旁邊的綠色箭頭來運行你的基準測試。測試完成後,Android Studio 會在 Run 視窗中印出 JSON 格式的詳細報告。

對於啟動速度 (StartupTimingMetric),關注:

timeToInitialDisplayMs: 首幀顯示時間。報告會給出 min, median, max 值,median (中位數) 是最值得我們長期追蹤的指標。

對於滾動性能 (FrameTimingMetric),關注:

frameDurationCpuMs: 每一幀在 CPU 上的處理時間。

P50 (中位數), P90, P95, P99 (百分位數) 這些指標。P99 代表了最差的 1% 的影格耗時,是衡量 Jank 的關鍵指標。這個數字越高,代表使用者體驗到的嚴重卡頓越多。

今日總結

今天,我們從「被動防守」轉向了「主動測量」,為我們的應用程式建立了自動化的性能體能測驗。

  • 我們區分了 Macrobenchmark (測量使用者互動) 和 Microbenchmark (測量函式) 的用途。

  • 我們學會了如何建立一個 Benchmark Moudle,並編寫了測量應用啟動和列表滾動性能的測試腳本。

  • 我們知道了如何解讀測試報告中的關鍵指標,如 timeToInitialDisplayMsframeDurationCpuMs (P99)

現在,我們擁有了一把客觀的「碼尺」,可以量化我們的性能優化成果,並將這些數據作為一個基準。當未來有新的程式碼提交時,我們可以再次運行測試,用數據來判斷它是否對性能造成了負面影響。

但手動運行終究不是長久之計。明天,我們將學習如何將這套「體能測驗」整合到我們的 CI/CD (持續整合/持續部署) 流程中,打造一個全自動化的性能哨兵,為我們的應用程式品質站崗。

我們明天見!


上一篇
# Day 26:【資源戰爭】嚴格模式 (StrictMode) 的應用
下一篇
# Day 28:【自動化戰爭】在 CI/CD 中運行 Benchmark
系列文
Android 性能戰爭:從 Profiler 開始的 30 天優化實錄28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言