Table of contents
My app on the Google play store
Introduction
I originally posted this on stack overflow, HERE
This is a bit of a deep dive I did after reading the Lifecycle of composables documentation. I would highly recommend that you read that documentation as it will give you a deeper understanding on what the heck goes on in compose
This is an intermediate level post. However, if you are a beginner I still think you could benefit from reading this blog post
What should be recomposed?
- When considering what composable should be recomposed, the compose compiler fist checks each distinct composable. We can use the documentation to define
distinct
as:
The instance of a composable in Composition is identified by its call site. The Compose compiler considers each call site as distinct. Calling composables from multiple call sites will create multiple instances of the composable in Composition.
call site : is the source code location in which a composable is called. This influences its place in Composition, and therefore, the UI tree
- so basically a composable is
distinct
if it is called in different spots in your code, even if the composables are the same:
Column {
YourComposable()
YourComposable()
}
- Both instance of
YourComposable()
are considereddistinct
by the compiler So if a composable is
distinct
(called from different places in your code) the compose compiler will know to only recompose the composable that has a state changeHowever, what happens when you have a for loop like this:
@Composable
fun MoviesScreen(movies: List<Movie>) {
Column {
for (movie in movies) {
// MovieOverview composables are placed in Composition given its
// index position in the for loop
MovieOverview(movie)
}
}
}
MovieOverview
is being called from the samecall site
(not distinct). To combat this scenario the compose compiler will use theexecution order in addition to the call site to keep the instances distinct
This will work fine as long as values are only removed and added to the bottom of the list(index of length-1). But once the list changes by either adding to the top or the middle of the list. Or by removing or reordering items ,it'll cause a recomposition in all MovieOverview calls whose input parameter has changed position in the list
if you have a list of length 100 and you insert at item at index 50, then all the composables from index 99-50 will get recomposed even though they have not had their state changed
The solution to this is the key composable
- the key composable allows the compose compiler to identify each composable as distinct and eliminate the wasteful recompositions
- the
key
must be unique to the list and will crash if it is not
@Composable
fun MoviesScreenWithKey(movies: List<Movie>) {
Column {
for (movie in movies) {
key(movie.id) { // Unique ID for this movie
MovieOverview(movie)
}
}
}
}
- The code block above can now have its items, rearranged, removed and added to at any index and no wasteful recompositions will occur.
What is the LazyColumn items key parameter purpose ?
- It serves the exact same role. LazyColumn just has built-in support for the key composable
@Composable
fun MoviesScreenLazy(movies: List<Movie>) {
LazyColumn {
items(movies, key = { movie -> movie.id }) { movie ->
MovieOverview(movie)
}
}
}
- If we did not provide the
key
and tried to remove, add or reorganize we would face the exact same wasteful recompositions mention earlier
Resources
Lifecycle of composables documentation
Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.
Top comments (0)