診斷穩定性問題

如果發生不必要或過度重組造成的效能問題,建議您對應用程式的穩定性進行偵錯。本指南會介紹幾種完成這項作業的方法。

版面配置檢查器

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

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

Compose 編譯器報表

Compose 編譯器可以輸出穩定性推論的結果,以供檢查。透過此輸出,您可以決定哪些可組合項可略過,以及哪些可組合項不行。後續章節會摘要說明如何使用這些報表,但如需詳細資訊,請參閱技術說明文件

設定

根據預設,系統不會啟用編譯器編譯器報表。您可以透過編譯器標記啟用這些 API。確切設定會因專案而異,但對於大多數專案,您可以將下列指令碼貼到根 build.gradle 檔案中。

Groovy

subprojects {
  tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
        }
    }
}

Kotlin

subprojects {
    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
        }
    }
}

執行工作

如要對可組合項的穩定性進行偵錯,請按照下列方式執行工作:

./gradlew assembleRelease -PcomposeCompilerReports=true

輸出內容範例

這項工作會輸出三個檔案。以下是 JetSnack 的輸出範例。

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

可組合函式報表

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 可組合項可完全重新啟動、可略過且穩定版。儘管並非強制要求,但通常不建議採取這種做法。

另一方面,讓我們再看看另一個範例。

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
)

HighlightedSnacks 可組合函式無法略過。Compose 不會在重組期間略過此動作。即使參數中沒有任何參數變更,也會發生這種情況。原因在於 unstable 參數 snacks

課程報表

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, ListMap 等標準集合類別最終是介面。因此,基礎實作仍有可能變動。

舉例來說,您可以編寫 val set: Set<String> = mutableSetOf("foo")。變數為常數,且其宣告的類型不可變動,但實作方式「仍然」可以變動。Compose 編譯器只會查看宣告的類型,因此無法確定這個類別的不變性。因此,系統會將 tags 標示為不穩定。