Jetpack Compose: Getting Started

Aug 1 2023 · Kotlin 1.8.10, Android 13, Android Studio Flamingo

Part 3: Jetpack Controls

18. Understanding Recomposition

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 17. State Management in Jetpack Compose Next episode: Part 3 Quiz: Jetpack Controls

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 18. Understanding Recomposition

With the Imperative UI model, in order to change a piece of the UI, you usually call a setter method on the UI element. For example, if you want to change the text of a TextView, you would call the setText() method on the TextView and pass in the new text that you want to display.

With the Declarative UI model, in order to change a piece of the UI, you usually change the state of the application. For example, if you want to change the text of a Text composable, you would change the value of the state variable that is passed into the Text composable.

In doing that, we usually cause the Composable function to be recomposed. Recomposition is the process of rebuilding the UI. When a Composable function is recomposed, the Composable function is called again and the UI is rebuilt.

Recomposition is a very powerful feature of Jetpack Compose. However, it is also a feature that you need to be careful with. If you are not careful, you can end up with a lot of unnecessary recompositions. This can cause your app to be slow and unresponsive.

An example of this is when recomposition depends on a state variable that is changed very frequently. For example, if you have a state variable that is changed every time the user types a character in an EditText field, this can cause a lot of unnecessary recompositions.

Heavy computation in a Composable function should be passed on to a background thread or Coroutine and the result should be passed into the Composable function. This will prevent the Composable function from being recomposed unnecessarily.

Code in a Composable function on many ocassions may look like it is executed in a sequential order. However, this is not always the case. If you have a Composable function that calls other Composables, those Composables may be executed in a different order than they are called.

Given the following example:

@Composable
fun Sample(){
    HomePage()
    NotificationsPage()
    ProfilePage()
}

Calls to HomePage(), NotificationsPage() and ProfilePage() may be executed in any order. This is because Jetpack Compose uses a lazy evaluation strategy. This means that Composables are only executed when they are needed.

Jetpack Compose can execute Composables in parallel. This means that Composables can be executed at the same time. This is because Jetpack Compose uses a lazy evaluation strategy. This means that Composables are only executed when they are needed.

Due to this, Jetpack Compose can take advantage of multi-core processors. This can improve the performance of your app.

In order to make sure your app will behave consistently during recomposition, you should make sure that your Composables are side-effect free. This means that your Composables should not have any side effects. For example, calling the same Composable multiple times should not change the state of the application.

Composables should only change the state of the UI using callbacks such as onClick and onValueChanged. This will ensure that your app will behave consistently during recomposition.

Parallel Compositions

Do this:

@Composable
fun TestPage(){
    var clicks by remember { mutableStateOf(0) }
    Column(){
        Button(onClick = { clicks++ }) {
            Text(text = "Click Me")
        }
        Text(text = "Clicked $clicks times")
    }
}

Do not do this:

@Composable
fun TestPage(){
    var clicks by remember { mutableStateOf(0) }
    Column(){
        Button(onClick = { }) {
            Text(text = "Click Me")
            clicks++
        }
        Text(text = "Clicked $clicks times")
    }
}

Recomposition Skips

Once a portion of your UI is declared invalid by a state change, Jetpack Compose will recompose that portion of the UI. However, Jetpack Compose will not always recompose the UI. Jetpack Compose will skip recomposition if the UI is already up to date.

A Text Composable can be recomposed deep within the UI tree but other Composables in the UI tree may not need to be recomposed. This is because the UI tree is already up to date.

Let us get a recap of what we have learned in this session.

  • Recomposition is the process of rebuilding the UI.
  • Recomposition is triggered when the state of the application changes.
  • Composable functions can be executed in any order.
  • Composable functions can be executed in parallel.
  • Jetpack Compose will skip recomposition if the UI is already up to date.
  • Recomposition is an optimistic process. Compose will expect to complete recomposition. However, if the state changes again, Compose will cancel the current recomposition and start a new one.
  • Composable functions can run infinitely. If recompositions are not handled properly, this can cause UI jank.