Technologies Natives

Jetpack Compose: Is Every Class from Another Module Unstable?

(Edited on April 4th, 2024)

In June 2023, I attended Mobilis in Mobile in Nantes, which focused on mobile development. During the first conference, Vincent Auguin discussed best practices in development with Jetpack Compose. I was particularly interested in one piece of information he shared: any class from another module is considered unstable. This surprised me, as I had not noticed any performance issues in my own applications developed with Jetpack Compose.

If you're new to Compose, you absolutely must watch this conference (a video recording was made and will be available shortly). If the video is still not available by the time you read this article, Ben Trengrove explained roughly the same things at the Android Dev Summit in 2022.

In Jetpack Compose, the stability of a parameter determines whether a component needs to be rendered again or not when its parent is recomposed. If a class is wrongly considered unstable, this can lead to a decrease in the application's display performance. Given that many applications are now built with a multi-module architecture, it's common to use classes from other modules in a Jetpack Compose component.

To check if this issue still exists with the latest versions of Compose (1.6.4) and the compose compiler (1.5.11), I conducted a test using the Layout Inspector of Android Studio, which allows displaying the recompositions of each composable.

Here is an example of the code I used for the test:


To force recomposition, it is enough to have an action that changes the content of the composable. If the parameter of ++code>ComposableUsingModel++/code> was stable, it would not recompose.

So, I added a composable with a parameter corresponding to a ++code>data class++/code> considered stable for intra-module use. I placed this composable in a parent and forced its rendering on a click. Unfortunately, the test results confirmed that the problem persists.

The left column indicates the number of recompositions, while the right column shows the number of recompositions avoided due to parameter stability.

How to avoid this problem while keeping my multi-module architecture?

Now that we are aware of the stability problem of classes from other modules in Jetpack Compose, it's time to think about solutions to avoid this issue while maintaining a multi-module architecture.

No way to integrate a UI framework into my business layers

A possible solution would have been to annotate the class in question with ++code>@Stable++/code> and run the compose compiler in the module where my model class is stored. However, this would violate my well-segmented architecture. Even if it's just a simple annotation, it could pose a problem if I want to migrate my project to Kotlin Multiplatform. Therefore, it's better to find another solution.

I strengthen the onion architecture of my Android application

Each layer of my current architecture (network, database, business) manipulates objects specific to that layer. The UI currently uses objects from my business layer. By giving my UI layer objects that are only manipulated within this layer, I can better segment my application. The solution I propose is to convert my business objects into UI objects at the time of passing them to my composable. Of course, my composable and the type of its parameter must be defined in the same module.

There were two possible solutions for this. Since the compose compiler 1.5.5 there is a third solution that is simpler and let me use my model objects in the UI layer.

Solution 1: Copy the model class

Solution 2: Wrap the model object in a stable class

Solution 3: Use the stability configuration file (the simplest)

By using one of these solutions, I can pass objects to my composable without compromising the stability of the parameters.

Conclusion

It is crucial to consider the stability of component parameters in Jetpack Compose to avoid undesirable recompositions. This is especially true for classes coming from other modules, which are considered unstable by default, such as LocalDateTime, for example. Since compose compiler 1.5.5 it’s simple to avoid this stability issue with a configuration file. The other two solutions make your onion architecture even better.However, the Compose compiler is very efficient; even if a composable is recomposed, its sub-components will not be recomposed if their parameters are stable, which explains why I didn't notice the problem in my application: it is present but the impact is minor (in my case).

Resources

The website of Mobilis in mobile

The Android Dev Summit 2022 video on Compose performance

The Android documentation for stability configuration file

Développeur mobile ?

Rejoins nos équipes