Blog Infos
Author
Published
Topics
, , , ,
Published
Photo by Marc Sendra Martorell on Unsplash

 

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.

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Stability_ImmutabilityTheme {
val (isChecked, onChecked) = remember { mutableStateOf(false) }
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
) {
Checkbox(
checked = isChecked,
onCheckedChange = onChecked
)
ContactList(
contactListState = ContactListState(
names = listOf("name1", "name2", "name3", "name4"),
)
)
}
}
}
}
}
@Composable
fun ContactList(
contactListState: ContactListState
) {
if (contactListState.isLoading) {
CircularProgressIndicator()
} else {
Text(text = contactListState.names.toString())
}
}
data class ContactListState(
val names: List<String>,
val isLoading: Boolean = false,
)
view raw ContactList.kt hosted with ❤ by GitHub

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
subprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
project.buildDir.absolutePath + "/compose_compiler",
)
compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
project.buildDir.absolutePath + "/compose_compiler",
)
}
}
view raw .kt hosted with ❤ by GitHub

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.

  1. app_release-classes.txt -> A report on the stability of classes
  2. app_release-composables.txt -> A report on the restartability and skippability of the composables.
  3. app_release-composables.csv -> A csv version of the above text file.
  4. app_release-module.json -> Contains some overall stats.

After running the task, open up the app_release-composables.txt file and we will see all composable functions and each will be marked with whether they are restartable, skippable.

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?

OUR VIDEO RECOMMENDATION

, ,

Migrating to Jetpack Compose – an interop love story

Most of you are familiar with Jetpack Compose and its benefits. If you’re able to start anew and create a Compose-only app, you’re on the right track. But this talk might not be for you…
Watch Video

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer for Jetpack Compose
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engin ...
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer f ...
Google

Jobs

No results found.

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; StringIntFloatImmutableList types are stables parameters.
Unstable parameters:
  • If a composable has a unstable parameters, Compose always recomposes it even if the parameters have not changed.
  • For example; ListMapSet types are unstable parameters. Also var declarations on Data class is unstable.
val numbers: List<Int> = mutableListOf(1, 2, 3)

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:

Github — Linkedin

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
In this part of our series on introducing Jetpack Compose into an existing project,…
READ MORE
blog
In the world of Jetpack Compose, where designing reusable and customizable UI components is…
READ MORE
blog

How to animate BottomSheet content using Jetpack Compose

Early this year I started a new pet project for listening to random radio…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu