Composition: esencia, construcción del árbol de UI en Compose

Autor: IT Sectr Publicado: 2026-06-27 Tiempo de lectura: 7 min

Composition es el proceso central en Jetpack Compose, durante el cual se construye un árbol de UI vivo a partir de funciones Composable descriptivas que se muestra en pantalla. A diferencia del sistema View de Android, donde los diseños se cargaban desde XML y se convertían en objetos inmutables, Composition funciona como un sistema dinámico: las funciones se ejecutan, crean slots en memoria, forman una jerarquía de nodos y la vinculan con el estado. Según Google Android Developers, 2026, comprender Composition es fundamental para optimizar el rendimiento de las aplicaciones Compose.

Puntos clave

  • Composition es la ejecución de funciones Composable para construir el árbol de UI
  • Slots son celdas de memoria que almacenan parámetros y estado de cada función
  • Posición en Compose (Positional Memorization) vincula el estado a un lugar en el código
  • Primer pase Composition crea el árbol de UI inicial al iniciar la pantalla
  • CompositionLocal pasa datos a través del árbol sin parámetros explícitos

Qué es Composition en Jetpack Compose

Composition es el proceso de ejecución de funciones Composable, que da como resultado una representación interna de la interfaz de usuario como un árbol de nodos. Cada nodo de este árbol corresponde a un componente integrado (Text, Button, Image) o a una llamada a una función Composable definida por el usuario. Composition no crea directamente objetos View de Android — construye una descripción abstracta que luego es procesada por las fases de Layout y Drawing.

La característica clave de Composition es su reiniciabilidad. Cada función Composable dentro de la composición puede reiniciarse en cualquier momento si sus parámetros de entrada o los objetos de estado que lee han cambiado. El sistema no reinicia todo el árbol — solo aquellas funciones que realmente dependen de los datos modificados.

Técnicamente, Composition se gestiona a través de Composer — un motor interno que el compilador Kotlin incorpora en cada función Composable. Composer escribe información sobre qué funciones fueron llamadas, con qué parámetros y en qué orden en slots (grupos de posición). En llamadas posteriores, Composer compara los nuevos datos con los almacenados y decide si reiniciar.

Cómo se construye el árbol de UI durante Composition

El proceso de construcción del árbol de UI comienza con la llamada al método setContent dentro de una Activity o Fragment. Este método crea la Composition inicial y comienza a ejecutar la función Composable raíz. Luego, cada función Composable anidada añade sus nodos al árbol, formando una jerarquía: Row contiene Text y Button, Column contiene Image y Card, y así sucesivamente.

Cada nodo del árbol recibe una clave de posición única, basada en su posición en el código fuente. Esta clave se utiliza para identificar el nodo durante ejecuciones posteriores. La clave de posición es la razón por la que el orden de llamada de las funciones Composable no debe depender de condiciones: si en una ejecución se llama A -> B, y en la siguiente B -> A, Compose no podrá coincidir los nodos antiguos con los nuevos.

kotlin
@Composable
fun AppScreen() {
    Column {                     // Nodo Column (posición 1)
        HeaderSection()            // Nodo HeaderSection (posición 2)
        ContentSection()           // Nodo ContentSection (posición 3)
        FooterSection()            // Nodo FooterSection (posición 4)
    }
}

@Composable
fun HeaderSection() {
    Row {                       // Nodo Row (posición 2.1)
        Text("Título")         // Nodo Text (posición 2.2)
        Icon(...)                // Nodo Icon (posición 2.3)
    }
}

En este ejemplo, cada llamada recibe una posición basada en el orden en el código. Column (posición 1) contiene tres nodos hijos (posiciones 2, 3, 4). HeaderSection añade dos nodos hijos más (2.1, 2.2, 2.3). Si en la siguiente recomposición ContentSection se llama antes que HeaderSection, Composer no podrá coincidir correctamente los nodos — de ahí la regla: el orden de las llamadas a funciones Composable debe ser estable.

Gestión del estado en Composition

El estado en Composition se gestiona a través de objetos de tipo State<T>. Cuando una función Composable lee un valor de State mediante una propiedad delegada (by), registra una dependencia de ese State. Cuando el valor cambia, todas las funciones que leyeron este State se marcan para reinicio en la siguiente fase de composición.

El mecanismo de registro de dependencias se llama sistema de snapshots. Cada vez que State cambia, un snapshot registra todos los cambios y notifica a Composer qué funciones dependen de ese State. Es importante entender: leer State dentro de código no Composable (por ejemplo, en una lambda onClick) no registra una dependencia — solo la lectura dentro de una función Composable o en lambdas ejecutadas en el contexto de composición.

El sistema de snapshots funciona transaccionalmente: múltiples cambios de State dentro de un mismo evento se combinan en una transacción, evitando múltiples recomposiciones. Esto es especialmente importante al manejar gestos: un movimiento cambia varios objetos State, pero Compose realiza solo una recomposición.

kotlin
@Composable
fun StateExample() {
    var text by remember { mutableStateOf("Hello") }
    var isVisible by remember { mutableStateOf(true) }

    Column {
        Text(text)  // registra dependencia de text

        if (isVisible) {  // registra dependencia de isVisible
            TextField(value = text, onValueChange = { text = it })
        }

        Button(onClick = { isVisible = !isVisible }) {
            Text(if (isVisible) "Ocultar" else "Mostrar")
        }
    }
}

Cambiar text provoca la recomposición solo de Column, Text y TextField. Column, Button y la condición isVisible permanecen sin cambios. Este aislamiento de la recomposición es una ventaja clave de Compose sobre los sistemas que redibujan toda la pantalla. Cada función Composable rastrea solo aquellos objetos State que lee directamente.

Composition vs Recomposition: diferencias clave

Composition y Recomposition son dos modos diferentes de ejecutar funciones Composable. Composition ocurre una vez cuando se crea la pantalla: el sistema ejecuta todas las funciones Composable con valores iniciales y construye el árbol de UI inicial. Recomposition ocurre múltiples veces cuando los datos cambian: el sistema reinicia solo aquellas funciones que dependen del estado modificado.

Modo Composition activa todos los nodos del árbol, asigna slots para cada función y registra todos los descendientes. Recomposition funciona de forma selectiva: Compose compara los valores nuevos y antiguos de los parámetros de cada función, y si no han cambiado — la función no se ejecuta (skipping).

Composition y Recomposition difieren en costo. La primera Composition es más cara porque requiere la construcción completa del árbol y la asignación de slots. Recomposition es más barata, especialmente si la mayoría de las funciones son estables — sus parámetros se comparan con equals, y Compose omite su invocación. Para máximo rendimiento, se debe buscar que la mayoría de las recomposiciones afecten al menor número posible de funciones.

CaracterísticaCompositionRecomposition
Cuándo ocurreUna vez, en la primera visualizaciónMúltiples veces, al cambiar datos
AlcanceTodo el árbolSolo funciones modificadas
Comparación de parámetrosNo se realizaSe realiza para skipping
Creación de slotsSí, todos los slots se creanSolo para nuevos nodos

CompositionLocal: paso de datos a través del árbol

CompositionLocal es un mecanismo para pasar datos implícitamente a través del árbol de composición. Resuelve el problema cuando un parámetro debe pasarse a través de docenas de funciones Composable anidadas que no lo usan directamente. En lugar de una cadena explícita de parámetros, los datos se establecen en el nivel superior y se leen en cualquier función anidada a través de CompositionLocal.current.

MaterialTheme es el ejemplo más conocido de CompositionLocal. Todos los componentes de Compose leen colores, tipografía y formas a través de MaterialTheme.colorScheme, MaterialTheme.typography, MaterialTheme.shapes, sin recibirlos a través de parámetros. Los desarrolladores pueden crear sus propios CompositionLocal para datos como el usuario actual, configuraciones de localización o configuración de pantalla.

Una limitación importante: CompositionLocal no debe usarse para datos que cambian con frecuencia (posición de desplazamiento, texto en un campo de entrada). Un componente que lee CompositionLocal se reinicia cada vez que el valor cambia, por lo que para datos dinámicos es mejor usar parámetros explícitos o State. CompositionLocal es óptimo para datos de configuración que cambian raramente o nunca.

kotlin
val LocalUser = compositionLocalOf<User?> { null }

@Composable
fun AppRoot(user: User, content: @Composable () -> Unit) {
    CompositionLocalProvider(LocalUser.provides(user)) {
        content()
    }
}

@Composable
fun UserAvatar() {
    val user = LocalUser.current  // lectura sin parámetro explícito
    AsyncImage(model = user?.avatarUrl, contentDescription = "Avatar")
}

CompositionLocalProvider crea un ámbito dentro del cual LocalUser.current devuelve el valor especificado. UserAvatar lee el usuario sin pasar explícitamente el parámetro a través de funciones intermedias. Esto es especialmente valioso en jerarquías profundas donde los datos solo se necesitan en unos pocos nodos hoja.

Preguntas frecuentes

Qué sucede si se cambia el State durante Composition

Cambiar State durante Composition programa una nueva recomposición que se ejecutará después de que finalice la actual. No se produce un bucle infinito: Compose garantiza que cada recomposición se realiza en una transacción separada del sistema de snapshots.

Cuánto tiempo toma Composition de una pantalla compleja

En dispositivos modernos, Composition de una pantalla con 50–100 funciones Composable toma 1–5 ms. Google recomienda mantenerse dentro de los 16 ms para un fotograma de 60fps. Si Composition excede este límite, use LazyColumn o divida la pantalla en funciones más pequeñas.

Se puede iniciar Composition manualmente

El inicio manual directo de Composition no es posible — es gestionado por Composer automáticamente. Sin embargo, se puede forzar una recomposición cambiando State o llamando a invalidate() en el composable raíz si se tiene acceso a CompositionContext.

En qué se diferencia Composition de la jerarquía View en Android clásico

La jerarquía View es un árbol inmutable de objetos Java que se crea una vez. Composition es un árbol virtual que se reconstruye cada vez que los datos cambian. View almacena su estado en variables de instancia, Composition — en slots vinculados a la posición de llamada de la función.

Cómo maneja Composition la eliminación de nodos

Si una función Composable deja de ser llamada (por ejemplo, una condición if se vuelve false), Composition elimina su nodo y activa la limpieza de DisposableEffect. Cuando reaparece (if vuelve a ser true), se crea un nuevo nodo — el antiguo no se restaura.

Resumen

  • Composition es el proceso de ejecutar funciones Composable para construir un árbol de UI vinculado al estado
  • Composer gestiona slots, registra llamadas a funciones y compara parámetros durante la recomposición
  • Sistema de snapshots registra dependencias de funciones del State y combina cambios en transacciones
  • Composition se ejecuta una vez al inicio, Recomposition — al cambiar datos
  • CompositionLocal pasa datos de configuración a través del árbol sin una cadena explícita de parámetros
  • Posición de una llamada a función sirve como su identificador único en el árbol de composición
  • Recomendación: mantenga las funciones Composable pequeñas con parámetros inmutables para un skipping eficiente

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también