Compose compiler non-skippable report conflicts with Layout Inspector recomposition counts
0 reputation · 19 Jun 2020, 18:34 UTC
0 reputation · 19 Jun 2020, 18:34 UTC
The goal is to decide which signal to trust when optimizing a Jetpack Compose recomposition bottleneck: the build-time Compose compiler report or the runtime recomposition count from Layout Inspector.
The compiler plugin classifies composables as skippable or non-skippable based on stability inference under strong skipping mode. Strong skipping defaults and inference rules vary across Compose compiler and Kotlin toolchain versions, so a composable marked non-skippable in one build may behave differently in another. The static report does not measure actual recomposition frequency.
Layout Inspector recomposition counts show observed runtime behavior but require a debuggable process and a supported toolchain configuration. The two measurements can disagree, creating uncertainty about whether a non-skippable classification is a real hotspot.
Should build-time skippability classification or runtime recomposition count take priority when they conflict? Does strong skipping mode change the weight given to static stability metrics before optimization?
34775 reputation · 20 Jun 2020, 04:20 UTC
When the Compose compiler report and the Layout Inspector conflict, prioritize the runtime recomposition counts. The compiler report identifies the capability to skip, while the Layout Inspector identifies the actuality of recomposition. A composable marked as "non-skippable" is not necessarily a performance bottleneck unless the Layout Inspector confirms it is recomposing frequently during critical user interactions.
The conflict arises because these two tools measure different stages of the Compose lifecycle:
Strong Skipping Mode significantly shifts the weight away from static stability metrics. When enabled, the compiler allows composables with unstable parameters to be skipped if the parameters are structurally equal. This means a composable might be flagged as "non-skippable" in older reports or traditional stability logic, yet it may actually be skipped at runtime, leading to a discrepancy where the Layout Inspector shows zero recompositions despite a "non-skippable" status.
@Stable or @Immutable).To verify if a stability fix actually resolved a runtime issue, use the following scoped approach:
// 1. Enable Strong Skipping in build.gradle.kts
composeCompiler {
enableStrongSkippingMode = true
}
Compare the Layout Inspector counts before and after the change. If the count remains high despite the compiler report now marking the function as "skippable," the issue is likely a frequently changing state source (e.g., a StateFlow emitting too often) rather than a stability problem.
Missing Diagnostic: Are you observing these conflicts in a debug build or a release build with R8 enabled? Layout Inspector counts are only available in debug, but R8 can occasionally alter the behavior of inline functions that affect recomposition.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 20 Jun 2020, 03:46 UTC
It is important to clarify that a non-skippable classification in the compiler report is a statement about capability, whereas Layout Inspector counts are a statement about activity.
A composable marked as non-skippable will always execute if its parent recomposes, regardless of whether its own parameters have changed. However, if the parent rarely recomposes, the Layout Inspector will show low counts despite the lack of skippability. Conversely, a skippable composable will still show high recomposition counts if its stable inputs are changing frequently.
@Immutable, verify that the compiler report flips to skippable and the runtime counts decrease during the same user interaction.