Increase the Performance in Jetpack Compose Part 4

Youssef Hachicha
2 min readJun 17, 2023

--

Unnecessary recomposition is a huge deal when it comes to increasing performance in our app, so today we are going to look at an example of how you can read your state and how doing it wrong will affect your app performance

let’s take a look at this example:

@Composable
fun Screen_() {
val counter = remember {
mutableStateOf(0)
}
Column(Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = {
counter.value++
}) {
Text(text = "Increase", fontSize = 40.sp)
}
val HeavyCalculation = 1000 * 2000.00.pow(5)
Composable1(text = "${counter.value}")
Composable2(text = "$HeavyCalculation")
println("Composition Composable Column")
}

}
@Composable
fun Composable1(text: String) {
println("Composition Composable 1")
Text(text, fontSize = 40.sp)
}
@Composable
fun Composable2(text: String) {
Text(text, fontSize = 25.sp)
}

In our screen we have a counter state, a column that has a button when clicked will increase the state, a HeavyCalculation variable that will simulate some heavy calculation, and two Composables, one will display the counter value and the other to display the heavy calculation value.

if you run the app and increase the counter by clicking on the Button, you will not face any problems but under the hood, there is a problem which is related to performance, if this was a real project with heavier calculation and more code it will definitely affect your app so let’s take a look on what’s under the hood.

the problem here is that we read our counter value inside of the column scope and that’s by passing it like so :

Composable1(text = "${counter.value}")

why is this a problem you may ask?

when you read this value like so, what compose will do, it will basically look at the nearest parent of this composable, which is our Column and then it recomposes, that happens because if a state changes compose will recompose and since here the state that has been changed is read in the Colum scope, then not only our Composable1 will be recomposed but also our Column too

so to solve this we should read our counter value inside of the Composable 1 function, that way it will recompose alone, and that way we would not have unnecessary recomposition of the Column not just that but whenever our Column recomposes our heavy calculation will be calculated again resulting in more performance issues

so we should only read state only where it’s actually needed and for our example here we do this using lambda function:

@Composable
fun Screen_() {
val counter = remember {
mutableStateOf(0)
}
Column(Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = {
counter.value++
}) {
Text(text = "Increase", fontSize = 40.sp)
}
val HeavyCalculation = 1000 * 2000.00.pow(5)
Composable1(onText = {"${counter.value}"})
Composable2(text = "$HeavyCalculation")
println("Composition Composable Column")
}

}
@Composable
fun Composable1(onText: ()-> String) {
println("Composition Composable 1")
Text(onText(), fontSize = 40.sp)
}
@Composable
fun Composable2(text: String) {
Text(text, fontSize = 25.sp)
}

we made a change in Composable 1 by passing a parameter lambda function that takes nothing and returns a string since we have invoked the onText() inside of our Composable 1 and then the counter.value will only be executed inside of Composable 1 scope.

hope this helps.

--

--