https://kotlinlang.org logo
Title
g

Guilherme Almeida

03/22/2022, 5:36 PM
Hey there 👋 When searching for composable screens that could be recomposing unnecessarily I found out a screen which is basically a
LazyColumn
with mostly
TextFields
inside I noticed they were all recomposing on every key stroke for any of the fields. So if I type in something in the first field, the other fields, even though they did not change their value, will also recompose. After experimenting a bit I pinned it down to using the
onFocusChanged
modifier for these text fields. After removing the
onFocusChanged
modifier the text fields seem to skip composition. Is this the expected behaviour ? Quick repro (I am using the the recomposeHighlighter to visualize recompositions):
val state = remember {
      List(20) { it to "" }.toMutableStateMap()
    }

    LazyColumn(Modifier.fillMaxSize()) {
      itemsIndexed(state.values.toList()) { index, string ->
        TextField(
          value = string,
          onValueChange = { state[index] = it },
          modifier = Modifier
            .recomposeHighlighter()
            .onFocusChanged {  }
        )
      }
    }
👀 2
m

myanmarking

03/22/2022, 7:46 PM
If the onfocuschanged lambda content calls something not stable, it is possible it may be the cause. What are you doing in onfocuschanged?
g

Guilherme Almeida

03/22/2022, 8:29 PM
I also thought that but it happens even when it is empty, like in the example I provided
m

myanmarking

03/22/2022, 8:48 PM
Hm ok. Is that composable declared inside a fragment by any chance?
p

Paul Woitaschek

03/22/2022, 8:53 PM
@Guilherme Almeida It is because it can’t omit recomposition as long as it’s not in its own composable
With one big composable, its inputs seem to be everything that’s before that code
g

Guilherme Almeida

03/22/2022, 9:02 PM
Ah interesting 🤔 In the app the text field is passed in through two composables (by passing a composable lambda), but the composable itself is created in the main composable I guess
I guess if you try to pass in the modifier from the main composable it will also recompose right?
m

myanmarking

03/22/2022, 9:06 PM
ToMutableStateMap, is that stable?
g

Guilherme Almeida

03/22/2022, 9:06 PM
I can test it a bit more tomorrow, thank you very much 🙏
I would expect it to be, and without the modifier recomposition occurs as expected 🤔
m

myanmarking

03/22/2022, 9:09 PM
Oh. The second item recompose is the focus change it makes sense
g

Guilherme Almeida

03/23/2022, 12:12 PM
So after testing it a bit more the problem seems to be where the
onFocusChanged
modifier is created, so If the modifier is created in the main composable it recomposes for every new state there, if it is inside its own composable then it only recomposes when the state has changed. Wrapping the modifier with
remember
also works, but does not seem ideal