@Stable And @Immutable in Jetpack compose

App Dev Insights
3 min readJun 2, 2024

--

In Jetpack Compose, @Stable and @Immutable are annotations used to inform the Compose compiler about the properties of certain classes or functions regarding their stability and immutability. Understanding these concepts is essential for optimizing recompositions and improving the performance of your composable functions.

@Stable

@Stable is an annotation to tell the Compose compiler that this object might change, but when it changes, Compose runtime will be notified.

It is used to mark classes or functions that are guaranteed to produce the same output when called with the same parameters, and they do not change over time. This helps Compose understand that the annotated object will not change unexpectedly, thus reducing unnecessary recompositions.

Usage

  1. Classes: Marking a class as @Stable indicates that the class's instances are stable and their properties will not change unexpectedly.
  2. Functions: Marking a function as @Stable indicates that the function is stable, meaning it always produces the same result given the same inputs and does not cause side effects.
@Stable
data class Person(val name: String, val age: Int)

In the above example, the Person class is annotated with @Stable, indicating that an instance of Person is stable and its properties will not change unexpectedly.

@Immutable

@Immutable is an annotation to tell Compose compiler that this object is immutable for optimization, so without using it, there will be unnecessary re-composition that might get triggered.

It is a stronger guarantee than @Stable. It is used to mark classes or functions whose instances are completely immutable. Once an instance of an @Immutable class is created, none of its properties can change.

Usage

  1. Classes: Marking a class as @Immutable indicates that all properties of the class are immutable.
  2. Functions: Marking a function as @Immutable indicates that the function does not modify any state and always returns the same result for the same inputs.
@Immutable
data class Address(val street: String, val city: String)

In the above example, the Address class is annotated with @Immutable, indicating that an instance of Address is completely immutable.

Differences and Practical Implications

  • Stability vs. Immutability: @Stable means the properties do not change unexpectedly, but they can change if explicitly updated. @Immutable means the properties can never change once initialized.
  • Performance Optimization: By annotating classes and functions correctly with @Stable and @Immutable, you provide Compose with more information to optimize recompositions, leading to better performance.
  • Recomposition Triggers: When Compose knows that a class or function is stable or immutable, it can avoid recomposing UI unnecessarily, which enhances performance.

Example

Here is an example to illustrate the difference

@Stable
class Counter {
var count: Int = 0
}

@Immutable
data class User(val id: Int, val name: String)

@Composable
fun CounterDisplay(counter: Counter) {
Text("Count: ${counter.count}")
}

@Composable
fun UserDisplay(user: User) {
Text("User: ${user.name}")
}
  • In CounterDisplay, the Counter class is @Stable, meaning counter.count can change, but it won't trigger unexpected recompositions unless explicitly changed.
  • In UserDisplay, the User class is @Immutable, meaning once a User instance is created, it will not change, ensuring the UI does not recompose unnecessarily.

By using these annotations appropriately, you can help Compose optimize your UI rendering and improve the overall performance of your application.

The compiler treats both identically but

  • using @Immutable is a promise that the value will never change.
  • using @Stable is a promise that the value is observable and if it does change listeners are notified.

https://stackoverflow.com/questions/68575936/what-do-the-stable-and-immutable-annotations-mean-in-jetpack-compose

--

--