Ejemplo práctico 1: Estado observable
Objetivo
Entender el funcionamiento de un observable y las diferencias entre utilizar remember { mutableStateOf(false) } y remember { false }.
Desarrollo
La clase MainActivity es la típica configuración de una actividad con Jetpack Compose, donde se establece el tema y el Scaffold, desde donde se llama a la función composable RememberVsMutableStateDemo:
1class MainActivity : ComponentActivity() {
2 override fun onCreate(savedInstanceState: Bundle?) {
3 super.onCreate(savedInstanceState)
4 enableEdgeToEdge()
5 setContent {
6 ExampleT1_01Theme {
7 Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
8 RememberVsMutableStateDemo(Modifier.padding(innerPadding))
9 }
10 }
11 }
12 }
13}Observa el código del método RememberVsMutableStateDemo, en el se muestran dos bloques similares pero con comportamientos diferentes:
1@Composable
2fun RememberVsMutableStateDemo(modifier: Modifier = Modifier) {
3 Surface(modifier = modifier.fillMaxSize()) {
4 Column(
5 modifier = Modifier
6 .padding(16.dp)
7 .fillMaxSize(),
8 verticalArrangement = Arrangement.spacedBy(24.dp)
9 ) {
10
11 // 1. Estado observable: cambia y la UI se actualiza.
12 Card {
13 Column(
14 modifier = Modifier.padding(16.dp),
15 verticalArrangement = Arrangement.spacedBy(12.dp)
16 ) {
17 Text(
18 text = "Estado observable con mutableStateOf",
19 style = MaterialTheme.typography.titleMedium
20 )
21 var checked by remember { mutableStateOf(false) }
22 Row(
23 verticalAlignment = Alignment.CenterVertically,
24 horizontalArrangement = Arrangement.spacedBy(12.dp)
25 ) {
26 Switch(
27 checked = checked,
28 onCheckedChange = { checked = it }
29 )
30 Text(
31 if (checked) "Estado: ACTIVO (se recompone)" else "Estado: INACTIVO (se recompone)"
32 )
33 }
34 Text(
35 text = "Aquí usamos un State<Boolean>. Cambiar su valor notifica a Compose y la UI se recompone."
36 )
37 }
38 }
39
40 // 2. Valor recordado NO observable: no hay recomposición al reasignar la variable local.
41 Card {
42 Column(
43 modifier = Modifier.padding(16.dp),
44 verticalArrangement = Arrangement.spacedBy(12.dp)
45 ) {
46 Text(
47 text = "Valor recordado sin estado observable",
48 style = MaterialTheme.typography.titleMedium
49 )
50
51 // OJO: esto recuerda "false" una vez, pero NO es State<T>.
52 var naive = remember { false }
53
54 Row(
55 verticalAlignment = Alignment.CenterVertically,
56 horizontalArrangement = Arrangement.spacedBy(12.dp)
57 ) {
58 // La UI LEE 'naive' pero cambiarlo no provoca recomposición.
59 Switch(
60 checked = naive,
61 onCheckedChange = { newValue ->
62 // Esto cambia la variable local, pero NO notifica a Compose.
63 naive = newValue
64 println("Desde el Switch: $naive")
65 }
66 )
67 Text(
68 if (naive) "Valor leído: TRUE (no observable)" else "Valor leído: FALSE (no observable)"
69 )
70 }
71
72 Button(
73 onClick = {
74 // También “cambia” la variable local, pero la UI no se enterará.
75 naive = !naive
76 println("Desde el Button: $naive")
77 }
78 ) {
79 Text("Intentar alternar (no actualizará la UI)")
80 }
81
82 Text(
83 text = "Este bloque usa un Boolean 'recordado' pero no observable. " +
84 "Reasignarlo no dispara recomposición, por lo que la UI no refleja los cambios."
85 )
86 }
87 }
88
89 // Nota pedagógica opcional
90 AssistChip(
91 onClick = {},
92 label = { Text("Consejo: si necesitas UI reactiva, usa State<T> (p. ej., mutableStateOf).") }
93 )
94 }
95 }
96}-
Estado observable con
mutableStateOf:- La variable
checkedse define comovar checked by remember { mutableStateOf(false) }. - Esto crea un estado observable. Cuando el usuario interactúa con el
Switchy cambia su valor, la UI se recompone automáticamente para reflejar el nuevo estado. - El texto del
Switchmuestra “Estado: ACTIVO” o “Estado: INACTIVO” según el valor dechecked, y este texto se actualiza dinámicamente. - Cada vez que
checkedcambia, Compose detecta el cambio y vuelve a ejecutar la función composable, actualizando la interfaz de usuario.
- La variable
-
Valor recordado sin estado observable:
- La variable
naivese define comovar naive = remember { false }. - Esto recuerda el valor “false” una vez, pero no es un estado observable. Cambiar
naiveno provoca recomposición. - Cuando el usuario interactúa con el
Switcho elButton, la variablenaivecambia internamente, pero la UI no se actualiza para reflejar estos cambios. - El texto del
Switchmuestra “Valor leído: FALSE” o “Valor leído: TRUE” según el valor denaive, pero este texto no se actualizará nunca.
- La variable
Conclusión
Este ejemplo ilustra claramente la diferencia entre usar un estado observable (mutableStateOf) y un valor recordado no observable (remember { false }). Para que la UI sea reactiva y se actualice automáticamente cuando los datos cambian, es esencial utilizar estados observables en Jetpack Compose.