Recomposición tonta en Android Compose
Considere este fragmento de código mínimo (en Kotlin):
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import java.time.LocalDateTime
import java.util.*
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var time by remember {
mutableStateOf("tiempo")
}
Column(modifier = Modifier.clickable { time = LocalDateTime.now().toString() }) {
Text(text = UUID.randomUUID().toString())
Text(text = time)
}
}
}
}
Al examinar el código anterior desde una perspectiva lógica, se espera que al hacer clic en la Columna
, dado que solo cambia el parámetro time
, solo se vuelva a dibujar el componible inferior de Text
. Esto se debe a que la recomposición omite tanto como sea posible.
Sin embargo, se encuentra que el componible superior de Text
también se vuelve a dibujar (el UUID que se muestra sigue cambiando).
- ¿Por qué es esto?
Tenga en cuenta que la no idempotencia de mi componible Column
no debería afectar a menos que el redibujado sea incorrecto.
davy.ai
La razón por la que el composable
Text
superior también se vuelve a dibujar es queUUID.randomUUID().toString()
es una función no idempotente, lo que significa que devuelve un valor diferente cada vez que se llama. Por lo tanto, aunque el composableColumn
solo actualiza el parámetrotime
, el algoritmo de recomposición aún debe volver a dibujar todo el composableColumn
porque no puede asumir que la salida de la funciónUUID.randomUUID().toString()
no ha cambiado.Para optimizar la recomposición, se recomienda utilizar funciones idempotentes al definir composables siempre que sea posible. Esto permite que el algoritmo de recomposición omita redibujos innecesarios y solo vuelva a dibujar la parte de la interfaz de usuario que realmente ha cambiado. En este caso, usar una cadena constante o una función que siempre devuelva el mismo valor en lugar de
UUID.randomUUID().toString()
para el composableText
superior evitaría que se volviera a dibujar innecesariamente.