診斷穩定性問題

如果因不必要或過度重組而發生效能問題,請對應用程式的穩定性進行偵錯。本指南概述幾種做法。

版面配置檢查器

Android Studio 的版面配置檢查器可讓您查看應用程式中正在重組的可組合項,並顯示 Compose 重組或略過元件的次數。

版面配置檢查器中的重組和略過計數

Compose 編譯器報表

Compose 編譯器可以輸出穩定性推論結果,供您檢查。您可以根據這項輸出內容,判斷哪些可組合函式可略過,哪些不可略過。以下子節將摘要說明如何使用這些報表,如需詳細資訊,請參閱技術說明文件。

設定

Compose 編譯器報表預設為停用。您可以使用編譯器標記啟用這些功能。確切設定會因專案而異,但如果專案使用 Compose 編譯器 Gradle 外掛程式,您可以在每個模組的 build.gradle 檔案中加入以下內容。

  android { ... }

  composeCompiler {
    reportsDestination = layout.buildDirectory.dir("compose_compiler")
    metricsDestination = layout.buildDirectory.dir("compose_compiler")
  }

建構專案時,系統現在會產生 Compose 編譯器報告。

輸出範例

reportsDestination 會輸出三個檔案。以下是 JetSnack 的輸出範例。

  • <modulename>-classes.txt:這個模組中類別穩定性的報告。範例。
  • <modulename>-composables.txt:這份報表會說明模組中可組合項的可重新啟動和可略過程度。範例。
  • <modulename>-composables.csv:可組合函式報表的 CSV 版本,可匯入試算表或使用指令碼處理。範例

可組合項報表

composables.txt 檔案會詳細說明指定模組的每個可組合函式,包括參數的穩定性,以及是否可重新啟動或略過。以下是 JetSnack 的假設範例:

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
  stable snackCollection: SnackCollection
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
  stable index: Int = @static 0
  stable highlight: Boolean = @static true
)

在這個範例中,SnackCollection 的每個參數都標示為 stable,因此 Compose 會使用結構相等性 (Object.equals()) 比較每個參數。雖然 stable 參數非常適合用於原始值和小型、扁平的資料類別,且 .equals() 檢查成本較低,但強制集合保留模型 (例如包裝 List<Snack> 的 SnackCollection) 為 stable 會導致 Compose 在每次重組時對每個項目呼叫 .equals()。啟用嚴格略過模式後,建議保留含有集合 unstable 的模型,這樣 Compose 就會改用例項相等性 (===) 比較這些模型。

或者,請考慮另一個在停用嚴格略過模式時產生的範例:

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  unstable snacks: List<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

停用嚴格略過模式時 (Kotlin 2.0.20 之前),HighlightedSnacks 可組合項無法略過,即使參數未變更,Compose 也不會在重組期間略過,因為 unstable 參數 snacks。

啟用嚴格略過模式 (Kotlin 2.0.20 以上版本的預設模式) 後,HighlightedSnacks 會標示為 skippable,Compose 則會使用例項相等性 (===) 比較 unstable 參數 snacks。因此,如果傳遞相同的 List 參照,Compose 會略過 HighlightedSnacks,只有在傳遞新分配的 List 例項時,才會重新組成。

課程報告

classes.txt 檔案包含指定模組中類別的類似報表。以下程式碼片段是 Snack 類別的輸出內容:

unstable class Snack {
  stable val id: Long
  stable val name: String
  stable val imageUrl: String
  stable val price: Long
  stable val tagline: String
  unstable val tags: Set<String>
  <runtime stability> = Unstable
}

Snack 的定義如下,供您參考:

data class Snack(
    val id: Long,
    val name: String,
    val imageUrl: String,
    val price: Long,
    val tagline: String = "",
    val tags: Set<String> = emptySet()
)

Compose 編譯器已將 Snack 標示為不穩定。這是因為 tags 參數的類型是 Set<String>。由於這不是 MutableSet,因此屬於不可變動類型。不過,Set、List 和 Map 等標準集合類別最終都是介面。因此,基礎實作可能仍會變動。

例如,您可以輸入 val set: Set<String> = mutableSetOf("foo")。變數是常數,宣告的類型不可變動,但實作仍可變動。Compose 編譯器只能看到宣告的類型,因此無法確定這個類別是否不可變動。因此,系統會將 tags 標示為不穩定。