Valeriy Katkov
Valeriy Katkov

Reputation: 40572

Should I use ConstraintLayout in Android Jetpack Compose for a better performance?

Before Jetpack Compose ConstraintLayout was the recommended way of building complex layouts since it allows to flatten UI hierarchies. See Manage complexity: layouts matter documentation section.

The most common case in which layout takes an especially long time is when hierarchies of View objects are nested within one another. Each nested layout object adds cost to the layout stage. The flatter your hierarchy, the less time that it takes for the layout stage to complete.

Is it still true in the Compose world?

Upvotes: 9

Views: 3067

Answers (2)

Thracian
Thracian

Reputation: 66674

It's actually the opposite. When performance is an issue you must be careful using ConstraintLayout in Jetpack Compose. ConstraintLayout calls MeasureLayout under the hood which comes with serious performance warning which is

@Composable
@UiComposable
@Deprecated(
    "This API is unsafe for UI performance at scale - using it incorrectly will lead " +
        "to exponential performance issues. This API should be avoided whenever possible."
)
fun MultiMeasureLayout(
    modifier: Modifier = Modifier,
    content: @Composable @UiComposable () -> Unit,
    measurePolicy: MeasurePolicy
) {
    // Rest of the code

}

@Composable
inline fun ConstraintLayout(
    modifier: Modifier = Modifier,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    crossinline content: @Composable ConstraintLayoutScope.() -> Unit
) {
    val measurer = remember { Measurer() }
    val scope = remember { ConstraintLayoutScope() }
    val remeasureRequesterState = remember { mutableStateOf(false) }
    val (measurePolicy, onHelpersChanged) = rememberConstraintLayoutMeasurePolicy(
        optimizationLevel,
        scope,
        remeasureRequesterState,
        measurer
    )
    @Suppress("Deprecation")
    MultiMeasureLayout(
        modifier = modifier.semantics { designInfoProvider = measurer },
        measurePolicy = measurePolicy,
        content = {
            val previousHelpersHashCode = scope.helpersHashCode
            scope.reset()
            scope.content()
            if (scope.helpersHashCode != previousHelpersHashCode) onHelpersChanged()
        }
    )
}

You can use when performance is not an issue and you don't want to build nested Composables there won't be an issue with ConstraintLayout, when layout is complex take MultiMeasureLayout warning message into consideration.

Upvotes: 5

Valeriy Katkov
Valeriy Katkov

Reputation: 40572

This is not the case in Compose. Use ConstraintLayout if it helps you to implement a layout but not because of performance concerns. See Compose ConstraintLayout documentation:

Note: In the View system, ConstraintLayout was the recommended way to create large and complex layouts, as a flat view hierarchy was better for performance than nested views are. However, this is not a concern in Compose, which is able to efficiently handle deep layout hierarchies.

Upvotes: 13

Related Questions