Performance In Jetpack Compose — Stability & Immutability
Tolga Pirim on 2024-01-16
Performance In Jetpack Compose — Stability & Immutability
When a state change occurs in Jetpack Compose, it can automatically skip composable functions whose parameters have not changed. This ensures efficient rendering and improves performance. But in some situations it can’t perform this and have to recompose the composable
functions.
This article explains why the operation cannot be performed and how to improve the application’s performance.
In this example, there are a Checkbox and a Contact List composable
function that shows the contact list.


Using the Layout Inspector tool we can observe which composables
are recompose on any state change. When state change, the recomposed elements are highlighted by blinking in blue. At the same time, we can see how many composable functions have been recomposed and how many have been skipped in the Layout Inspector.
We can open Layout Inspector from Tools/Layout Inspector in Android Studio.
In this example, we change only the state of Checkbox, however the Contact List
composable have recomposed four times although never change parameters of the Contact List.
Restartable & Skippable In Jetpack Compose Functions
Before explaining the concepts of restartable and skippable, I’ll first explain what recomposition is.
Recomposition is the process of calling your composable functions again when inputs change. This happens when the function’s inputs change. When Compose recomposes based on new inputs, it only calls the functions or lambdas that might have changed, and skips the rest. — Android Documentation
The Compose compiler marks a function as restartable
and skippable
to determine whether it is skippable or restartable.
What is the Restartable and Skippable?
Restartable
Marking a function as restartable
indicates that it can be called again if any changes occur in its inputs.
Skippable
Marking a function as skippable
, it can be skip calling the function if the parameters haven’t changed since last call.
How Do We Know The Function Has Marked a Restartable and/or Skippable?
Enable the report of the Compose Compiler Metrics
Write the script above to the build.gradle.kts (Project) file.
To get the result of the report, we can run this command,
./gradlew assembleRelease -PcomposeCompilerReports=true
This task will generate four files in the build directory of each module under the compose_compiler file.

- app_release-classes.txt -> A report on the stability of classes
- app_release-composables.txt -> A report on the restartability and skippability of the composables.
- app_release-composables.csv -> A csv version of the above text file.
- app_release-module.json -> Contains some overall stats.
restartable scheme("[androidx.compose.ui.UiComposable]") fun ContactList( unstable contactListState: ContactListState )
This ContactList
composable is restartable but not skippable. Why?
The ContactListState
parameter has marked unstable. What does unstable mean in terms of stability, and how can I make it stable?
Stability
The stability of a composable’s parameters is crucial in determining whether it needs to be re-evaluated during recomposition in Compose.
Stable Parameters
- If the parameters of a composable are stable and have not changed during recomposition, Compose skips it.
- For example;
String
,Int
,Float
,ImmutableList
types are stables parameters.
- If a composable has a unstable parameters, Compose always recomposes it even if the parameters have not changed.
- For example;
List
,Map
,Set
types are unstable parameters. Alsovar
declarations onData class
is unstable.
Since standard Collection
classes are defined as interfaces in Kotlin, their underlying implementation may be unstable. The Compose compiler can’t be sure of the immutability of this class since it only sees the declared type, and will mark it as unstable.
Let’s see our ContactListState
data class. To see the report open up app_release-classes file.
unstable class ContactListState { unstable val names: List<String> stable val isLoading: Boolean <runtime stability> = Unstable }
As we mentioned above the list parameters is unstable. If a data class has unstable parameters, it will also be unstable.
Stable and Immutable Annotations
Immutable —As the name suggests, these hold data that is immutable. Since the data never changes, Compose can treat this as stable data.
@Immutable data class ContactListState( val names: List<String>, val isLoading: Boolean = false, )
Stable — These hold data that is mutable but notify Composition upon mutating.
@Stable data class ContactListState( val names: List<String>, val isLoading: Boolean = false, )
We could use either one. After making this change, let’s rerun the metrics and observe any changes.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun ContactList( stable contactListState: ContactListState )
The ContactList
composable is both restartable and skippable. And ContactList’s parameters is stable.


When the state changes, only CheckBox is recompose. Since any of the Contact List parameters has not changed and is stable, Compose can safely skip it.
Connect me:
Resources
- Android Documentation
- Composable metrics - Chris Banes
- Jetpack Compose Stability Explained - Ben Trengrove
- Stability in Jetpack Compose & Avoid Recomposition - Emre Memil
- Understanding @Stable, @Immutable, ImmutableCollection, and PersistentCollection in Jetpack Compose - Sherry Yuan
- Performance Optimization with @Stable and @Immutable in Jetpack Compose (Youtube Video) - Philipp Lackner