6

The Jetpack compose documentation says it can skip recomposition if all the inputs are stable and haven't changed. The definition of a type being stable goes like this...

A stable type must comply with the following contract:

  1. The result of equals for two instances will forever be the same for the same two instances.
  2. If a public property of the type changes, Composition will be notified.
  3. All public property types are also stable.

I cannot understand this clearly. Can someone explain to me how compose checks if a type is Stable?? I can understand if compose determines a type as stable, then it will check for equality with equals method. But how to say whether a class is stable so that we can understand and favour smart recomposition as much as possible?

I tried playing around and found the following.

This data class Student is not stable, even if I pass the same instance again, its recomposing


data class Student(
     var id:Int=1,
     var name:String="Anonymous")

However, the following class is treated as stable and favors smart recomposition when we pass the same instance again

This class is stable when all the public parameters are changed to val

data class Student(
     val id:Int=1,
     val name:String="Anonymous")

So, I can understand that all the public properties should be immutable. But to my confusion, the following class is also treated as Stable and favors smart recomposition. Why?

This MainActivityVM class is considered Stable when passing like

@Composable
fun StudentList(viewModel:MainActivityVM){
   ...
}

class MainActivityVM : ViewModel() {

   val studentNames = mutableStateListOf<Student>()
   var textInputDialogState by mutableStateOf(TextInputDialogState())

   var publicMutableProperty:String = "This is mutable"
}

So, I could not figure out exactly how compose checks for stable types. Can someone help me to understand this so that I can efficiently support smart recomposition in my code?

z.g.y
  • 5,512
  • 4
  • 10
  • 36
Sundaravel
  • 464
  • 5
  • 16

1 Answers1

4

I cannot understand this clearly. Can someone explain to me how compose checks if a type is Stable??

These all are stable by default

  • All primitive value types: Boolean, Int, Long, Float, Char, etc.
  • Strings
  • All Function types (lambdas)

Compose compiler looks at the class and the class cannot be inferred as stable if any one of the field is

  • mutable (it is associated with a var property)
  • has a non-stable type (like lists, map etc.. all data structures are unstable by default, as they are not immutable but read-only)

Also, you can rely on compiler and let compiler tell you the stability of a class when in doubt.

You can use

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        freeCompilerArgs += [
                "-P",
                "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${buildDir}/composeReports"
        ]
    }
}

It will create classes in composeReports, you can check if compose can infer the stability.

stable class YourClass {
  stable val value: CornerSize
  <runtime stability> = Stable
}

The generated report will look like above in pseudo-code format.

https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md#classes--classestxt

Ritt
  • 3,181
  • 3
  • 22
  • 51