Compose Performance: Measure Before You Optimize Recomposition

Jetpack Compose recomposition and performance visualization

Jetpack Compose uses state-driven UI, but a high recomposition count is not automatically a performance defect. A small composable may recompose cheaply, while an expensive layout, image operation, or I/O task may cause visible jank.

Begin with real measurement

Reproduce the problem in a release-like build with R8 enabled. Measure a real user journey such as cold start, opening a detail screen, scrolling a feed, or changing a filter.

Use system traces, Layout Inspector, Macrobenchmark, and Baseline Profiles to identify whether time is spent in composition, layout, drawing, image work, or I/O.

Keep state reads close to the work

If a screen-level composable reads rapidly changing state and passes it through a large tree, more content may be reconsidered than necessary. Move reads closer to the element that needs them or defer frequently changing reads with lambda-based modifiers.

Give lazy content stable identity

LazyColumn {
    items(
        items = articles,
        key = { article -> article.id },
    ) { article ->
        ArticleRow(article)
    }
}

Stable keys help Compose preserve item identity when content changes position.

Use stability tools carefully

Do not add @Stable or @Immutable unless the type actually satisfies the contract. False stability annotations can produce stale UI.

Measure first, change the smallest relevant part, and measure again.

Sources: Compose performance, Baseline Profiles, Strong skipping

About the Author

You may also like these