One Off the Slack: Compose and Performance

Some Android Developer asked:

Is Compose prone to problems similar to which a deeply nested Android ViewGroup suffers? I mean double layout taxation, slow measure/layout phases, etc. On Android, we always tried to build a flat view hierarchy, without deep nesting or weights. And what with Compose?

The original historical reason for the flat view hierarchy was to avoid running into a StackOverflowError — if the view hierarchy got to 10+ layers deep, we might literally run out of stack space. Fortunately, we have a bigger stack nowadays, so that particular concern has fallen away.

As Zach Klippenstein noted, Compose uses a single-pass layout system. Or, as Google’ Sean McQuillan noted in an earlier Slack thread:

It helped me build a mental model for compose layout to realize that it’s intended to be single pass and it works by modifying the (min, max) constraints passed to children… This takes some getting used to coming from Android views. The main advantage you get is that there’s no way to express non-performant O(2^n) UIs using wrap_content or layout_weight in Compose.

This does not mean that all performance problems are solved by magic. As Zach put it:

A slow layout is going to be slow no matter what, so if you have a really complex ConstraintLayout, it will be slower than a simple Row.

Or, as Google’s Romain Guy wrote:

Deep nesting means deeper call stacks, more code to execute, more state to track, potentially more complex drawing trees, more allocations, etc. No matter what, doing less is always going to beat doing more 🙂

The fact that Compose is function-based means that we can sometimes leverage inline functions to improve performance. dev16 should see inline versions of Row and Column, according to Google’s Leland Richardson, with significant gains as a result:

We saw around 6x improvement in a number of our benchmarks.

Read the original thread in the kotlinlang Slack workspace. Not a member? Join that Slack workspace here!