Remembering the State in Jetpack Compose

When starting to work with Jetpack Compose (now that it is in beta 🎉) and stateful components, we easily get used to define values based on a mutable state which are also remembered. But there are two independent concepts when we write a line of code like below:

  • mutableState* family functions return an observable value for Compose. It creates a MutableState that allows Compose to magically react when the contained value changes.
  • remember on the other hand makes the computation passed to the lambda execute once (not exactly once, but just during the composition). This is valid not just to avoid a state to recreate/reinitialize when the recomposition happens, but also to “cache” expensive computations.

To get a better understanding of how both functions work together we are going to see what is the result for a set of examples implementing a simple click counter.

Remembering the state

Here we have a remembered state defined under a Surface. The state value is read on a Text contained in a Button:

clicks value is populated from an observable type (State<T>) which is also remembered across any recomposition the Surface may experience.

So even if the Surface were recomposed, the value of clicks will be remembered. This is why the counter works as expected.

Don’t remember the state

Let’s remove now the remember “wrapping” around the state:

It may be surprising/unexpected that the click counter keeps incrementing. Why isn’t the state recreated? Just because the composable that contains it (the Surface) is not being recomposed. And why isn’t the Surface recomposing? Because none of its direct children depends on the value of the state (the Button itself doesn’t depend on the state).

No state

Here the click counter is defined as a regular variable:

It is pretty clear that this won’t make the click counter update. Defining the counter as a regular variable doesn’t make Compose aware of updates on the variable, so recomposition won’t even happen here. This is why State is needed, to make Compose aware of a value that needs to be observed to recompose composables depending on the state when the value changes.

No remember but…

State again is not remembered here, but in addition to that the button enabled property depends on the clicks state.

And the counter is broken again. The reason is that when the value clicks changes, now the Surface gets recomposed, which makes the state value come back to the initial state (because the value is not being saved/remembered).

Conclusion

Be aware of defining state properly, don’t rely on a state value not being read at some point in the hierarchy. If the value should be kept then remember it, and if must survive activity/process recreation then use rememberSaveable.

I hope this helps understanding why state is such an important topic in Compose, and how do we need to take care of properly managing it!

Impure developer and functional programming enthusiast

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store