La filosofía de Jetpack Compose es muy distinta a la tecnología previa en el desarrollo de aplicaciones Android.
Cuando uno desarrolla una aplicación con Compose las funciones componibles superiores envían el estado a las funciones componibles inferiores, y de las inferiores disparan eventos a la funciones superiores para que actualicen su estado.
Veamos un ejemplo con dos funciones componibles que utilicen este principio.
Confeccionar una aplicación que mediante dos botones, uno que incremente en uno un texto y el otro botón lo disminuya en 1.
La interfaz visual debe ser:
Crearemos un proyecto llamado 'Compose8' e implementaremos el siguiente código:
package com.tutorialesprogramacionya.compose8 import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { SelectorNumerico() } } } @Composable fun SelectorNumerico() { var valorActual by remember { mutableStateOf(0) } BotonesSelector(valorActual = valorActual, presion = { valorActual += it } ) } @Composable fun BotonesSelector(valorActual: Int, presion: (Int) -> Unit) { Column() { Button(onClick = { presion(1) }) { Text(text = "Incrementar") } Text(text = "$valorActual",fontSize = 30.sp) Button(onClick = { presion(-1) }) { Text(text = "Decrementar") } } }
Hay que tener en claro que desde el MainActivity llamamos a la función componible 'SelectorNumerico':
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { SelectorNumerico() } } }
La primer función componible 'SelectorNumerico' administra el estado de nuestro selector numérico mediante la variable 'valorActual', luego llama a la segunda función componible llamada 'BotonesSelector' pansando el estado actual (es decir la variable valorActual) y la referencia de una función landa en el parámetro 'presion':
@Composable fun SelectorNumerico() { var valorActual by remember { mutableStateOf(0) } BotonesSelector(valorActual = valorActual, presion = { valorActual += it } ) }
La segunda función componible recibe como parámetros, primero el valor que debe mostrar el selector numérico y el segundo parámetro la referencia a la función lambda que deberá llamar cuando se presione alguno de los dos botones que compone la función:
@Composable fun BotonesSelector(valorActual: Int, presion: (Int) -> Unit) { Column() { Button(onClick = { presion(1) }) { Text(text = "Incrementar") } Text(text = "$valorActual",fontSize = 30.sp) Button(onClick = { presion(-1) }) { Text(text = "Decrementar") } } }
El flujo de estado y eventos con este modelo de programación es:
Lo más importante en este ejemplo es entender que cuando alguno de los botones es presionado se llama a la función presión pasando el 1 o -1 según el botón presionado:
Button(onClick = { presion(1) }) { Text(text = "Incrementar") }
Esto hace que se ejecute la función lambda que definimos en la primer función:
BotonesSelector(valorActual = valorActual, presion = { valorActual += it } )
El parámetro it recibe el 1 o -1 según el botón presionado y procedemos a actualizar la variable que almacena el estado 'valorActual', luego de esto Compose se encarga de actualizar en pantalla todas las funciones componibles que muestran dicho valor, en nuestro caso la función Text definida dentro de la función 'BotonesSelectores' y se procede a recomponer o redibujar:
Text(text = "$valorActual",fontSize = 30.sp)
Compose es muy eficiente cuando tiene que recomponer la pantalla, y en este caso no redibuja los dos botones, sino solo llama nuevamente a la función componible Text que reimprime el contendio de valorActual que ha sido modificado en la primer función.