# Tema 1 · Fundamentos y origen de los eventos

Programación Dirigida por Eventos · Grado en Ingeniería Informática · 2026/27

Qué significa que un programa esté dirigido por eventos: quién controla el siguiente paso, inversión de control, el vocabulario fuente / evento / receptor y el viaje de un suceso desde el mundo físico (polling, interrupciones, IRQ, ISR, driver, latencia) hasta tu código. Lo aplicamos reescribiendo agenda.kt como agendaeventos.kt y clasificando diez situaciones reales.

## El paradigma dirigido por eventos

_Flujo secuencial frente a flujo dirigido por eventos, inversión de control, el vocabulario fuente / evento / receptor y el viaje de un suceso desde el mundo físico hasta tu código: polling, interrupciones, IRQ, ISR, driver y latencia._

### ¿Quién controla el siguiente paso? · Teoría

Toda la asignatura gira alrededor de una pregunta muy sencilla: **¿quién decide cuál es el siguiente paso del programa?**

En los programas que habéis escrito hasta ahora la respuesta era obvia: el propio programa. Ejecuta la instrucción 1, luego la 2, luego la 3. Si lees el código de arriba abajo, sabes en qué orden va a pasar todo.

En un programa **dirigido por eventos** esa respuesta cambia: el **entorno** determina *cuándo* llega un suceso (un clic, un mensaje, un temporizador que vence, un sensor que se dispara) y la aplicación se limita a **reaccionar**.

| | Programa secuencial | Programa dirigido por eventos |
| --- | --- | --- |
| Quién decide el orden | El programa: 1 → 2 → 3 | El entorno decide cuándo llega cada suceso |
| Qué hace el código | Sigue su guion de principio a fin | Reacciona a lo que va ocurriendo |
| Orden de ejecución | Fijo, se lee en el código | Depende de cuándo llegan los eventos |

![Arriba, un programa secuencial: instrucción 1, instrucción 2, instrucción 3 y fin, en un orden fijo que decide el programa. Abajo, un programa dirigido por eventos: en la franja del entorno llegan un clic, un mensaje, un temporizador y un sensor en momentos irregulares de una línea de tiempo, y cada uno dispara una reacción en la franja de la aplicación.](/img/pde/tema-1/secuencial-vs-eventos.svg "Secuencial: el programa fija el orden. Dirigido por eventos: el entorno decide cuándo llega cada suceso")

> [!ANALOGIA] Receta frente a recepción de hotel
> Un cocinero con una receta decide el orden: pelar, cortar, freír. Un recepcionista no puede: no sabe si lo siguiente será una llamada, un cliente con una queja o un repartidor. Tiene preparada una respuesta para cada caso y la ejecuta **cuando el suceso llega**.

La Programación Orientada / Dirigida por Eventos (POE) es un **paradigma general**: el software reacciona a sucesos. Al terminar la unidad deberías poder:

- **Comprender** que la POE no es "cosa de ventanas", sino una forma general de organizar software que reacciona.
- **Distinguir** flujo secuencial y flujo dirigido por eventos.
- **Explicar** la cadena *estímulo externo → evento software → reacción*.
- **Reconocer** el paradigma en GUI, móviles, servidores, IoT y firmware.

> [!EXAMEN]
> En POE el orden de las reacciones depende del **momento en que llegan los eventos**, no del orden en el que escribiste los manejadores en el fichero.

**Preguntas**

**1.** En un programa dirigido por eventos, ¿qué determina el orden en que se ejecutan las reacciones?

   a) El orden en que están escritas las funciones en el fichero
   b) El momento en que llegan los eventos
   c) El orden alfabético de los nombres de los manejadores
   d) La prioridad que el compilador asigna a cada función

**2.** ¿Cuáles de estos programas siguen el paradigma dirigido por eventos?

   a) Una app móvil que reacciona a los toques en la pantalla
   b) Un script que lee un CSV, calcula la media y termina
   c) Un servidor web que atiende peticiones según van llegando
   d) El firmware de un termostato que reacciona a la interrupción de un sensor

### POO organiza piezas; POE organiza reacciones · Teoría

No confundas la POE con una alternativa a la POO. Responden a preguntas distintas:

<div class="cards">
  <div class="card"><h4>POO</h4><p>Organiza <b>piezas</b>: objetos, estado y métodos.</p></div>
  <div class="card"><h4>POE</h4><p>Organiza <b>reacciones</b>: sucesos, fuentes, receptores y reacciones.</p></div>
  <div class="card"><h4>Lo que añade la POE</h4><p>Qué ocurre, quién lo comunica y <b>cuándo</b> se ejecuta cada respuesta.</p></div>
</div>

En esta asignatura escribiréis POE **con** POO (Kotlin): los receptores serán objetos, lambdas o clases que implementan una interfaz.

## Inversión de control (IoC)

La idea central del paradigma tiene nombre propio: **inversión de control**.

- La aplicación **no inicia cada llamada** ni decide el orden completo.
- Es el **framework, el sistema operativo, una biblioteca o el hardware** quien invoca la reacción que tú registraste.
- Se resume en el **principio de Hollywood**: *«No nos llames; nosotros te llamaremos»*.

```kotlin
// Flujo convencional: MI código llama a la biblioteca, y yo decido cuándo
val texto = readLine()
procesar(texto)

// Inversión de control: entrego una reacción y OTRO decide cuándo llamarla
boton.setOnClickListener {
    procesar("clic")   // lo invocará el framework cuando el usuario pulse
}
```

Fíjate en la diferencia: en el primer bloque, `procesar` se ejecuta justo después de `readLine()`. En el segundo, al llegar a esa línea **no se ejecuta nada**: solo se *registra* el código. Se ejecutará más tarde, cero, una o cien veces, según lo que haga el usuario.

![Dos paneles. Flujo convencional: mi código llama a la biblioteca (readLine) y la biblioteca le devuelve el dato; mi código decide cuándo. Inversión de control: primero mi código registra una reacción (setOnClickListener) en el framework, el SO o el hardware; después es ese entorno el que, cuando ocurre el suceso, llama a mi reacción. Debajo, el principio de Hollywood: «No nos llames; nosotros te llamaremos».](/img/pde/tema-1/inversion-de-control.svg "Flujo convencional frente a inversión de control: cambia quién llama a quién")

> [!EXAMEN] La frase que hay que saber decir
> Flujo convencional: **mi código llama a la biblioteca**. Inversión de control: **el entorno llama a mi código**.

**Preguntas**

**3.** ¿Cómo se llama el principio que resume la inversión de control con la frase «No nos llames; nosotros te llamaremos»?

**4.** ¿Qué describe mejor la inversión de control?

   a) El programa invierte el orden de sus instrucciones para ir más rápido
   b) La POE sustituye a la POO, que deja de ser necesaria
   c) El entorno (framework, SO, biblioteca o hardware) invoca la reacción que la aplicación registró
   d) La aplicación llama a la biblioteca cada vez que necesita un dato

### Ejercicio: ¿hay inversión de control? · Ejercicio

Mira estos cinco fragmentos (Kotlin/Android y Arduino) y decide en cuáles **es otro quien decide cuándo se ejecuta tu código**.

```kotlin
// A
val n = readLine()!!.toInt()
println(n * 2)

// B
boton.setOnClickListener { contador++ }

// C
Handler(Looper.getMainLooper()).postDelayed({ mostrarAviso() }, 5000)

// D
val total = listOf(3, 4, 5).sum()
```

```cpp
// E (Arduino / ESP32)
attachInterrupt(digitalPinToInterrupt(PIN_BOTON), alPulsar, FALLING);
```

Pista para razonar cada uno: pregúntate **quién llama a la función** y **quién decide el momento**.

<details><summary>Ver razonamiento</summary>
<p><b>A</b>: tu código llama a <code>readLine()</code> y se queda esperando; cuando vuelve, sigue en el orden que tú escribiste. Flujo convencional.</p>
<p><b>B</b>: registras una lambda; el framework la invoca cuando el usuario pulsa. IoC (botón).</p>
<p><b>C</b>: entregas <code>mostrarAviso()</code>; el sistema la activa al vencer el tiempo. IoC (temporizador).</p>
<p><b>D</b>: llamas a <code>sum()</code> y obtienes el resultado al momento. Convencional.</p>
<p><b>E</b>: registras <code>alPulsar</code>; el hardware, a través de una interrupción, decide cuándo se ejecuta. IoC (sensor / pin).</p>
</details>

> [!TRUCO]
> Si en la línea donde aparece tu función **no se ejecuta nada todavía** (solo se pasa como parámetro para "más tarde"), casi seguro estás ante inversión de control.

**Preguntas**

**5.** ¿Qué fragmentos muestran inversión de control?

   a) A
   b) B
   c) C
   d) D
   e) E

**6.** En el fragmento C, ¿quién decide el momento exacto en que se ejecuta `mostrarAviso()`?

   a) La línea siguiente del código, que la llama explícitamente
   b) El sistema, al vencer el plazo de 5000 ms
   c) El usuario, al pulsar un botón
   d) Nadie: se ejecuta en cuanto se lee esa línea

### Vocabulario esencial: evento, fuente, receptor… · Teoría

Para hablar con precisión de eventos necesitamos cinco palabras. Apréndelas bien: aparecerán en todas las unidades.

| Término | Definición |
| --- | --- |
| **Evento** | Suceso relevante que el software puede comunicar y procesar. |
| **Fuente / emisor** | Componente, dispositivo o sistema que **origina o publica** el evento. |
| **Receptor** | Componente **interesado** en recibir la notificación. |
| **Notificación** | Comunicación que **entrega** el evento al receptor. |
| **Reacción** | Trabajo que realiza el receptor al **procesar** el evento. |

<div class="flow">
  <div><b>Fuente</b><small>origina el suceso</small></div>
  <div><b>Evento</b><small>qué pasa + datos</small></div>
  <div><b>Notificación</b><small>lo entrega</small></div>
  <div><b>Receptor</b><small>reacciona</small></div>
</div>

## Todo evento lleva información

Un evento no es solo "algo ha pasado". Lleva cuatro datos:

| Campo | Pregunta | Ejemplos |
| --- | --- | --- |
| **Tipo** | ¿Qué ocurrió? | clic, timeout, mensaje, temperatura alta |
| **Origen** | ¿Quién lo produjo? | botón, sensor, conexión, tarea |
| **Datos** | ¿Con qué información? | tecla, valor, coordenadas, contenido |
| **Instante** | ¿Cuándo? | marca de tiempo; ayuda a razonar sobre **orden y latencia** |

En código podría representarse así:

```kotlin
data class Evento(
    val tipo: String,     // "clic", "timeout", "temperatura_alta"
    val origen: String,   // "botonEnviar", "sensorNevera"
    val datos: Any?,      // tecla, valor leído, coordenadas…
    val instante: Long    // milisegundos desde el arranque, por ejemplo
)
```

> [!EXAMEN] Fórmula para memorizar
> **Evento = tipo + origen + datos + instante.** La fuente produce o detecta, el receptor procesa y la notificación los conecta.

**Preguntas**

**7.** ¿Qué información lleva todo evento, según el modelo de la unidad?

   a) Tipo
   b) Receptor
   c) Origen
   d) Datos
   e) Prioridad
   f) Instante

**8.** ¿Cómo se llama el componente **interesado** en recibir la notificación de un evento?

### Ejercicio: pon nombre a cada pieza · Ejercicio

Escenario: estás en un editor de texto con el cuadro de búsqueda abierto. **Pulsas la tecla Esc** y el cuadro se cierra.

Desmonta la escena con el vocabulario del paso anterior antes de mirar la solución:

| Pieza | Tu respuesta |
| --- | --- |
| Fuente | ¿? |
| Evento (tipo, origen, datos, instante) | ¿? |
| Notificación | ¿? |
| Receptor | ¿? |
| Reacción | ¿? |

<details><summary>Ver una solución</summary>
<p><b>Fuente</b>: el usuario a través del teclado (y el sistema que capta la pulsación).</p>
<p><b>Evento</b>: tipo «tecla pulsada»; origen: el teclado; datos: el código de la tecla Esc; instante: la marca de tiempo de la pulsación.</p>
<p><b>Notificación</b>: el sistema / framework entrega ese evento al componente que tiene el foco.</p>
<p><b>Receptor</b>: el manejador de teclado del cuadro de búsqueda.</p>
<p><b>Reacción</b>: cerrar el cuadro de búsqueda.</p>
</details>

> [!CUIDADO] Error típico
> Decir que la fuente es "la tecla Esc" y que el evento también es "la tecla Esc". Si dos columnas te salen iguales, algo falla: la **fuente** es quien origina (usuario + teclado); el **evento** es lo que ha pasado, con sus datos (pulsación de Esc).

**Preguntas**

**9.** En el escenario de la tecla Esc, ¿cuál es la **reacción**?

   a) La pulsación de la tecla
   b) El teclado
   c) Entregar el evento al cuadro de búsqueda
   d) Cerrar el cuadro de búsqueda

**10.** ¿Qué campo del evento permite distinguir esta pulsación de una pulsación de la tecla Intro?

   a) El instante
   b) Los datos (el código de la tecla)
   c) El origen
   d) El receptor

**11.** ¿Qué campo del evento ayuda a razonar sobre el **orden** y la **latencia**?

### Del mundo físico al software: polling o interrupción · Teoría

Un clic no aparece por arte de magia en tu `onClick`. Recorre cinco etapas:

<div class="flow">
  <div><b>1 · Estímulo</b><small>usuario, sensor, red, temporizador, dispositivo</small></div>
  <div><b>2 · Detección</b><small>hardware: polling o interrupción</small></div>
  <div><b>3 · Interpretación</b><small>driver/controlador y SO</small></div>
  <div><b>4 · Evento software</b><small>tipo, origen y datos</small></div>
  <div><b>5 · Reacción</b><small>notificación a la app y respuesta</small></div>
</div>

La etapa 2 merece atención: hay **dos formas** de detectar que algo ha ocurrido.

| | Polling | Interrupción |
| --- | --- | --- |
| Idea | Consulta repetida: «¿ha ocurrido algo?» | Una señal pide atención a la CPU cuando ocurre el suceso |
| Ventaja | Muy simple | La CPU puede hacer otro trabajo hasta recibirla |
| Inconveniente | Consume CPU y la respuesta depende de la frecuencia de consulta | Más compleja de configurar |

> [!ANALOGIA] El móvil en silencio
> **Polling**: miras el móvil cada cinco minutos para ver si te ha escrito alguien. Si el mensaje llega justo después de mirar, no te enteras hasta la siguiente vez. **Interrupción**: el móvil vibra y te avisa; mientras tanto puedes estudiar tranquilamente.

> [!IMPORTANTE]
> Si se consulta tarde, el evento se detecta tarde: con polling **aumenta la latencia de detección**.

![Dos líneas de tiempo. Polling: la CPU consulta a intervalos regulares si ha ocurrido algo; el suceso llega justo después de una consulta y no se detecta hasta la siguiente, y ese hueco es la latencia de detección. Interrupción: la CPU hace otro trabajo; cuando ocurre el suceso, la señal IRQ pide atención, la CPU ejecuta la ISR, interviene el driver y después la CPU sigue con lo suyo.](/img/pde/tema-1/polling-vs-interrupcion.svg "Polling frente a interrupción: con polling el suceso espera a la siguiente consulta")

```cpp
// Polling: el bucle pregunta una y otra vez
void loop() {
  if (digitalRead(PIN_BOTON) == LOW) {   // ¿ha pasado algo?
    encenderLed();
  }
  delay(100);                             // vuelve a preguntar dentro de 100 ms
}
```

**Preguntas**

**12.** Ordena las etapas del recorrido de un suceso, del mundo físico a la aplicación.

   Ordena: Detección · Estímulo · Evento software · Interpretación (driver y SO) · Reacción

**13.** ¿Cuál es el principal inconveniente del polling?

   a) Necesita un driver especial que no existe en microcontroladores
   b) Consume CPU y su tiempo de respuesta depende de la frecuencia de consulta
   c) Solo funciona con eventos de red
   d) La CPU no puede hacer nada más hasta que llega la interrupción

### IRQ, ISR y driver; latencia · Teoría

Tres siglas que en el examen **no** se pueden mezclar:

<div class="cards">
  <div class="card"><h4>IRQ</h4><p><i>Interrupt Request</i>: la <b>solicitud o señal</b> de interrupción que genera un dispositivo o controlador.</p></div>
  <div class="card"><h4>ISR</h4><p><i>Interrupt Service Routine</i>: el <b>código</b> que ejecuta la CPU para atender la interrupción.</p></div>
  <div class="card"><h4>Driver / controlador</h4><p><b>Software que traduce</b> los detalles del dispositivo a operaciones y datos utilizables por el sistema.</p></div>
</div>

> [!ANALOGIA] El timbre de casa
> La **IRQ** es el timbre que suena. La **ISR** es lo que haces al oírlo: dejar lo que estabas haciendo e ir a abrir. El **driver** sería quien traduce al visitante: "es el repartidor, trae un paquete para ti".

## Latencia: el tiempo hasta poder reaccionar

**Latencia** = tiempo desde que ocurre el estímulo hasta que la aplicación **puede** reaccionar.

No se genera en un único sitio: se **acumula** a lo largo de todo el recorrido.

<div class="flow">
  <div><b>Detección</b><small>polling o interrupción</small></div>
  <div><b>Driver</b><small>interpretación</small></div>
  <div><b>Transferencia</b><small>mover los datos</small></div>
  <div><b>Generación</b><small>crear el evento</small></div>
  <div><b>Entrega</b><small>notificar</small></div>
  <div><b>Reacción</b><small>tu código</small></div>
</div>

La capacidad de respuesta depende de **todo el recorrido**, no solo del código final. Optimizar tu `onClick` no sirve de nada si el retraso está en un polling lento.

![Las cinco etapas del recorrido de un suceso, de arriba abajo, con la capa en la que ocurre cada una: estímulo (mundo físico), detección por polling o interrupción con su IRQ (hardware), interpretación con la ISR y el driver y evento software con tipo, origen y datos (driver y SO), y reacción con la notificación a la app y tu código (aplicación). A la derecha, una línea naranja muestra cómo la latencia se va sumando desde t = 0: detección, driver y transferencia, generación del evento, entrega y reacción.](/img/pde/tema-1/recorrido-capas-latencia.svg "Cada capa del recorrido añade su parte de latencia")

> [!EXAMEN] Pregunta clave
> Ante un sistema que "va lento reaccionando": **¿en qué capa se está añadiendo tiempo?**

**Preguntas**

**14.** ¿Qué es una ISR?

   a) La señal eléctrica que un dispositivo envía para pedir atención
   b) El código que ejecuta la CPU para atender una interrupción
   c) El software que traduce los detalles de un dispositivo para el sistema operativo
   d) El tiempo que pasa desde el estímulo hasta la reacción

**15.** ¿Dónde puede acumularse latencia en el recorrido de un evento?

   a) En la detección (polling o interrupción)
   b) En el driver
   c) En la entrega del evento a la aplicación
   d) Únicamente en el código final de la aplicación
   e) En la propia reacción

### Ejercicio: ¿dónde se pierde el tiempo? · Ejercicio

Un ESP32 lee un pulsador con el `loop()` del paso 6: comprueba el pin y luego hace `delay(100)`.

```cpp
void loop() {
  if (digitalRead(PIN_BOTON) == LOW) encenderLed();
  delay(100);
}
```

Razona estas situaciones:

1. El usuario pulsa **justo después** de que el programa haya comprobado el pin. ¿Cuánto puede tardar, como mucho, en detectarse la pulsación (despreciando el tiempo de `digitalRead`)?
2. Si en vez de `delay(100)` pusiéramos `delay(10)`, ¿qué ganamos y qué perdemos?
3. Si registramos el pin con `attachInterrupt(...)`, ¿qué pasa con esa espera?

<details><summary>Ver razonamiento</summary>
<p>1. Hasta la siguiente consulta: casi <b>100 ms</b> de latencia de detección en el peor caso.</p>
<p>2. Detectamos antes (≈10 ms en el peor caso), pero la CPU pasa mucho más tiempo preguntando: más consumo para nada la mayoría de las veces.</p>
<p>3. La señal de interrupción (IRQ) avisa en cuanto ocurre el cambio y la CPU ejecuta la ISR: la latencia de detección deja de depender de la frecuencia de consulta, y la CPU puede hacer otro trabajo mientras tanto.</p>
</details>

> [!NOTA]
> Volveréis a este dilema en el laboratorio con el ESP32: es la misma decisión que toma cualquier firmware que tiene que reaccionar a un botón o a un sensor.

**Preguntas**

**16.** Con polling cada 100 ms, ¿cuántos milisegundos puede tardar como mucho en detectarse la pulsación? (escribe solo el número)

**17.** ¿Qué sigla designa la **señal** con la que el controlador del pin pide atención a la CPU?

### Ampliación: la POO como soporte de la POE · Teoría

> [!NOTA] Ampliación (contenido *stretch*)
> Este paso y el siguiente van más allá de lo obligatorio. Merece la pena leerlos: preparan la Unidad 2 (listeners y Observer).

La POO no sustituye al modelo de eventos: **lo hace extensible y desacoplado**. Tres mecanismos lo consiguen:

| Mecanismo | Qué aporta a la POE |
| --- | --- |
| **Interfaz** | Expresa el **contrato** de una reacción sin fijar la implementación. Una fuente puede notificar a receptores distintos mediante ese contrato común. |
| **Polimorfismo** | Distintos receptores comparten contrato y **reaccionan de forma diferente** a la misma notificación. |
| **Composición** | Objetos que colaboran para construir fuentes, receptores y cadenas de reacciones, **sin concentrar toda la lógica en una clase**. |

```kotlin
// Interfaz: el contrato de la reacción
interface ReceptorTemperatura {
    fun onTemperatura(grados: Double)
}

// Polimorfismo: mismo contrato, reacciones distintas
class Pantalla : ReceptorTemperatura {
    override fun onTemperatura(grados: Double) = println("Ahora: $grados °C")
}

class Alarma(private val umbral: Double) : ReceptorTemperatura {
    override fun onTemperatura(grados: Double) {
        if (grados > umbral) println("¡ALERTA! $grados °C")
    }
}

// Composición: la fuente guarda una lista de receptores
class Sensor {
    private val receptores = mutableListOf<ReceptorTemperatura>()
    fun registrar(r: ReceptorTemperatura) { receptores.add(r) }
    fun nuevaLectura(grados: Double) = receptores.forEach { it.onTemperatura(grados) }
}

fun main() {
    val sensor = Sensor()
    sensor.registrar(Pantalla())
    sensor.registrar(Alarma(25.0))
    sensor.nuevaLectura(30.0)
}
```

El `Sensor` no sabe si al otro lado hay una pantalla, una alarma o un registro en fichero: solo conoce la interfaz. Añadir un receptor nuevo **no obliga a tocar la fuente**.

**Preguntas**

**18.** ¿Cómo permite una interfaz que varias clases actúen como receptoras de la misma fuente?

   a) Obliga a que todas las clases hereden de la fuente
   b) Define un contrato común; la fuente notifica a través de él sin conocer la clase concreta
   c) Hace que la fuente ejecute todas las reacciones dentro de su propio código
   d) Impide que haya más de un receptor registrado a la vez

**19.** Al ejecutar `main()`, ¿cuántas líneas se imprimen?

### Ampliación: de Engelbart a los servidores · Teoría

> [!NOTA] Ampliación (contenido *stretch*)

## Hitos para entender la interacción moderna

<div class="cards">
  <div class="card"><h4>Douglas Engelbart</h4><p>Pionero de la interacción persona-ordenador; asociado al <b>ratón</b> y a la interacción directa.</p></div>
  <div class="card"><h4>Xerox PARC</h4><p>Centro de investigación que impulsó las <b>interfaces gráficas</b> y la interacción moderna.</p></div>
  <div class="card"><h4>WIMP</h4><p><b>W</b>indows · <b>I</b>cons · <b>M</b>enus · <b>P</b>ointer: ventanas, iconos, menús y puntero.</p></div>
</div>

Con una GUI el usuario puede hacer clic en cualquier sitio en cualquier momento: el programa ya no puede seguir un guion fijo. Por eso las interfaces gráficas **popularizaron** la POE… pero **no la definen**.

| Ámbito | Sucesos típicos |
| --- | --- |
| GUI y móviles | Clics, teclas, toques, ciclo de vida, sensores |
| Servidores | Conexiones, peticiones, mensajes, temporizadores |
| IoT y firmware | Sensores, actuadores, GPIO, interrupciones, temporizadores |

> [!IMPORTANTE]
> La POE aparece **donde un sistema reacciona a sucesos que no siguen un orden fijo**, haya o no pantalla.

## Inversión de control en cuatro situaciones

| Situación | Quién decide cuándo se reacciona |
| --- | --- |
| **Botón** | El usuario decide el clic; el framework invoca la reacción registrada. |
| **Temporizador** | La aplicación configura una reacción; el sistema la activa al vencer el tiempo. |
| **Mensaje de red** | La llegada del mensaje determina cuándo se ejecuta su procesamiento. |
| **Sensor** | El cambio medido determina cuándo se comunica un evento a sus consumidores. |

> [!RESUMEN]
> La pregunta siempre es la misma: **¿qué suceso decide cuándo se ejecuta la reacción?**

**Preguntas**

**20.** En el acrónimo WIMP, ¿qué significa la **P**? (en inglés o en español)

**21.** ¿Qué afirmación sobre la GUI y la POE es correcta?

   a) La POE solo existe en programas con interfaz gráfica
   b) La GUI popularizó la POE, pero el paradigma también está en servidores, IoT y firmware
   c) Los servidores no son dirigidos por eventos porque no tienen usuario delante
   d) Xerox PARC inventó la inversión de control para los servidores web

**22.** En un servidor que procesa mensajes de red, ¿qué determina cuándo se ejecuta el procesamiento de un mensaje?

   a) La llegada del mensaje
   b) El orden en que se declararon las funciones
   c) Un bucle que el programador recorre a mano llamando a cada función
   d) El usuario, pulsando un botón

### Repaso: mapa mental y autoevaluación · Repaso

> [!RESUMEN] Chuleta de la Unidad 1
> - **Secuencial**: el programa decide el orden (1 → 2 → 3). **Dirigido por eventos**: el entorno decide cuándo llega cada suceso y la app reacciona.
> - **POO** organiza piezas (objetos, estado, métodos); **POE** organiza reacciones (sucesos, fuentes, receptores, reacciones).
> - **Inversión de control**: el entorno llama a mi código. *«No nos llames; nosotros te llamaremos.»*
> - **Evento = tipo + origen + datos + instante.**
> - **Fuente** produce/detecta · **receptor** procesa · **notificación** los conecta · **reacción** es el trabajo del receptor.
> - **Estímulo → detección → interpretación → evento software → reacción.**
> - **Polling**: preguntar repetidamente (simple, gasta CPU, latencia según frecuencia). **Interrupción**: señal que pide atención (CPU libre mientras tanto).
> - **IRQ** = la señal · **ISR** = el código que la atiende · **driver** = traduce el dispositivo para el sistema.
> - **Latencia**: del estímulo a poder reaccionar; se acumula en **todas** las capas.

| Memoriza | Distingue | Explica |
| --- | --- | --- |
| POO organiza objetos; POE organiza reacciones. Evento = tipo + origen + datos + instante. | Fuente produce/detecta · receptor procesa · notificación conecta. | Polling vs. interrupción · IRQ vs. ISR · función del driver · significado de latencia. |

**Ampliación**: interfaces, polimorfismo y composición son las herramientas de POO para implementar POE. Engelbart, Xerox PARC y WIMP explican el origen de las GUI modernas; la POE se generaliza a servidores, IoT y firmware.

**Preguntas**

**23.** Un compañero dice: «La IRQ es la función que escribimos para atender el botón». ¿Qué le corriges?

   a) Nada, es correcto
   b) Esa función es el driver
   c) Esa función es la ISR; la IRQ es la señal o solicitud de interrupción
   d) Esa función es el polling

**24.** ¿Qué ventaja tiene la interrupción frente al polling?

   a) La CPU puede hacer otro trabajo hasta recibir la señal y la detección no depende de una frecuencia de consulta
   b) No necesita ningún tipo de hardware
   c) Elimina toda la latencia del sistema
   d) Permite que el programa decida el orden de los eventos

**25.** ¿En cuáles de estas situaciones hay inversión de control?

   a) Un botón cuyo listener invoca el framework al pulsarlo
   b) Un temporizador que activa una reacción configurada al vencer
   c) Un sensor cuyo cambio dispara la notificación a sus consumidores
   d) Una función que calcula el máximo de una lista y devuelve el resultado

**26.** ¿Cómo se llama el tiempo que transcurre desde que ocurre el estímulo hasta que la aplicación puede reaccionar?

### Solucionario

1. b) El momento en que llegan los eventos  
   El entorno decide **cuándo** llega cada suceso; la aplicación solo reacciona. Por eso el orden de ejecución depende de la llegada de los eventos, no del código fuente.
2. a) Una app móvil que reacciona a los toques en la pantalla; c) Un servidor web que atiende peticiones según van llegando; d) El firmware de un termostato que reacciona a la interrupción de un sensor  
   La app, el servidor y el firmware esperan sucesos que no controlan. El script del CSV decide él solo el orden de todo: es secuencial.
3. `hollywood`  
   Es el **principio de Hollywood**: tú registras la reacción y el entorno te llama cuando toca.
4. c) El entorno (framework, SO, biblioteca o hardware) invoca la reacción que la aplicación registró  
   En IoC la aplicación no decide cuándo se ejecuta su código: lo registra y es el entorno quien lo invoca. La última opción es justo el flujo convencional.
5. b) B; c) C; e) E  
   B (botón), C (temporizador) y E (interrupción de un pin) registran una reacción que invoca otro. A y D son llamadas normales: tu código llama y recibe la respuesta en ese mismo punto.
6. b) El sistema, al vencer el plazo de 5000 ms  
   La aplicación **configura** la reacción; el sistema la **activa** cuando vence el tiempo. Es uno de los cuatro casos clásicos de IoC: botón, temporizador, mensaje de red y sensor.
7. a) Tipo; c) Origen; d) Datos; f) Instante  
   Tipo (qué), origen (quién lo produjo), datos (con qué información) e instante (cuándo). El receptor no forma parte del evento: es quien lo procesa.
8. `receptor`  
   Es el **receptor**: recibe la notificación y ejecuta la reacción.
9. d) Cerrar el cuadro de búsqueda  
   La reacción es el **trabajo** del receptor: cerrar el cuadro. La pulsación es el evento, el teclado forma parte de la fuente y entregar el evento es la notificación.
10. b) Los datos (el código de la tecla)  
   Ambos eventos tienen el mismo tipo (tecla pulsada) y el mismo origen (teclado). Lo que cambia son los **datos**: el código de la tecla.
11. `instante`  
   El **instante**: cuándo ocurrió o se registró el suceso.
12. 1. Estímulo → 2. Detección → 3. Interpretación (driver y SO) → 4. Evento software → 5. Reacción  
   Estímulo → detección (polling o interrupción) → interpretación por driver y SO → evento software con tipo, origen y datos → notificación y reacción de la aplicación.
13. b) Consume CPU y su tiempo de respuesta depende de la frecuencia de consulta  
   Preguntar sin parar gasta CPU; preguntar poco retrasa la detección. La última opción describe justo lo contrario de una interrupción, que **libera** a la CPU.
14. b) El código que ejecuta la CPU para atender una interrupción  
   ISR = *Interrupt Service Routine*, la rutina (código) que atiende la interrupción. La primera opción es la IRQ, la tercera el driver y la cuarta la latencia.
15. a) En la detección (polling o interrupción); b) En el driver; c) En la entrega del evento a la aplicación; e) En la propia reacción  
   La latencia se acumula en detección, driver, transferencia, generación, entrega y reacción. Por eso la opción «únicamente en el código final» es falsa.
16. `100`  
   Si el suceso ocurre justo después de mirar, no se ve hasta la siguiente consulta: casi **100 ms** de latencia de detección.
17. `IRQ`  
   Es la **IRQ** (*Interrupt Request*). El código que la atiende es la ISR.
18. b) Define un contrato común; la fuente notifica a través de él sin conocer la clase concreta  
   La fuente solo conoce `ReceptorTemperatura`. Cualquier clase que implemente ese contrato puede registrarse, y cada una reacciona a su manera (polimorfismo).
19. `2`  
   Se notifica a los dos receptores: `Pantalla` imprime «Ahora: 30.0 °C» y `Alarma(25.0)` imprime la alerta porque 30.0 > 25.0. Total: **2** líneas.
20. `pointer`  
   WIMP = Windows, Icons, Menus, **Pointer** (puntero).
21. b) La GUI popularizó la POE, pero el paradigma también está en servidores, IoT y firmware  
   La GUI es una aplicación muy importante del paradigma, pero la POE se generaliza a cualquier sistema que reaccione a sucesos sin orden fijo: servidores, IoT y firmware.
22. a) La llegada del mensaje  
   En el caso del mensaje de red, es **su llegada** la que dispara el procesamiento: otro ejemplo de inversión de control.
23. c) Esa función es la ISR; la IRQ es la señal o solicitud de interrupción  
   La **IRQ** es la petición (la señal). La **ISR** es la rutina, el código que se ejecuta para atenderla.
24. a) La CPU puede hacer otro trabajo hasta recibir la señal y la detección no depende de una frecuencia de consulta  
   La interrupción libera a la CPU y avisa cuando ocurre el suceso. Pero no elimina **toda** la latencia: driver, entrega y reacción siguen sumando tiempo.
25. a) Un botón cuyo listener invoca el framework al pulsarlo; b) Un temporizador que activa una reacción configurada al vencer; c) Un sensor cuyo cambio dispara la notificación a sus consumidores  
   Botón, temporizador y sensor (y mensaje de red) son los cuatro casos clásicos de IoC. Calcular un máximo es una llamada convencional.
26. `latencia`  
   Es la **latencia**, y depende de todo el recorrido, no solo del código final.

## De agenda.kt a agendaeventos.kt

_Un menú de consola que lo decide todo, reescrito en cuatro piezas: evento, fuente, receptor y un bucle «tonto» que solo pide y entrega. Y dónde está ese bucle en Android._

### Un vocabulario, tres contextos · Teoría

Esta sesión práctica aplica el mismo vocabulario en tres sitios distintos:

| Bloque | Qué se hace | Tiempo |
| --- | --- | --- |
| **pde-plantilla** | Vistas clásicas de Android: un botón, un interruptor y sus listeners. ¿Quién decide el flujo y dónde están las reacciones? | 45 min |
| **pde-consola · agenda.kt** | Un menú de consola secuencial. El programa lo decide todo: pregunta, espera, elige, repite. | 20 min |
| **agendaeventos.kt** | El mismo programa reescrito en piezas separadas: fuente, evento y receptor. | 35 min |
| **Debate** | Diez situaciones de la vida real (lección siguiente). | opcional |

## El vocabulario de hoy

<div class="cards">
  <div class="card"><h4>Fuente</h4><p>Quién origina el suceso: una persona, un sensor, un temporizador, otro programa. En consola: el teclado y la función que lo lee.</p></div>
  <div class="card"><h4>Evento</h4><p>El suceso concreto, con sus datos: «clic en Enviar», «timeout a los 5 s», «mensaje de Ana». En código: un valor de un tipo que lo representa.</p></div>
  <div class="card"><h4>Receptor</h4><p>El código que escucha y reacciona: un listener, una lambda, una función <code>manejar()</code>. Sabe qué hacer, no cuándo le toca.</p></div>
</div>

> [!IMPORTANTE] La pregunta guía de toda la sesión
> **¿Quién decide qué pasa y cuándo?**

En **pde-plantilla** la respuesta ya se intuye: escribís cosas como `boton.setOnClickListener { ... }` y nunca llamáis vosotros a esa lambda. Alguien la llama. En consola vamos a construir ese "alguien" a mano para ver qué hay dentro.

**Preguntas**

**1.** Según el vocabulario de la sesión, ¿qué sabe un receptor?

   a) Cuándo le toca ejecutarse, pero no qué hacer
   b) Qué hacer, pero no cuándo le toca
   c) Qué hacer y cuándo, porque él controla el bucle
   d) Nada: solo reenvía el evento a la fuente

**2.** En un programa de consola, ¿qué hace de fuente de eventos?

   a) La lista de tareas
   b) El `when` que elige la rama
   c) El teclado y la función que lo lee
   d) La función `println`

### agenda.kt: el programa que lo decide todo · Teoría

Este es el punto de partida, en versión plegada (el contenido de las ramas viene después):

```kotlin
fun main() {
    val tareas = mutableListOf<String>()
    var salir = false

    while (!salir) {                                  // 1. el bucle que espera
        println("\n--- Agenda de tareas ---")
        println("1. Añadir tarea")
        println("2. Listar tareas")
        println("3. Eliminar tarea")
        println("4. Salir")
        print("Elige una opción: ")

        when (readLine()?.trim()) {                   // 2. punto de bloqueo  3. el bucle decide
            "1" -> { /* añadir tarea */ }
            "2" -> { /* listar tareas */ }
            "3" -> { /* eliminar tarea */ }
            "4" -> { salir = true; println("Hasta luego.") }  // 4. la única salida
            else -> println("Opción no reconocida.")
        }
    }
}
```

1. **El bucle que espera.** Mientras nadie elija «Salir», el programa vuelve a preguntar. Nadie le avisa de nada: es **él** quien pregunta, una y otra vez.
2. **El punto de bloqueo.** `readLine()` detiene el programa hasta que el usuario pulsa Intro. Es la única fuente de sucesos, y está **enterrada dentro del bucle**.
3. **El bucle decide.** El `when` compara un texto y elige la rama. La lógica de qué hacer vive dentro del propio bucle.
4. **La única salida.** Poner `salir = true` es lo único que rompe el ciclo: el programa termina cuando él mismo lo decide.

Ahora las ramas desplegadas:

```kotlin
"1" -> {
    print("Descripción de la tarea: ")
    val desc = readLine() ?: ""          // ¡vuelve a leer del teclado dentro de la reacción!
    tareas.add(desc)
    println("Tarea añadida.")
}
"2" -> {
    if (tareas.isEmpty()) println("No hay tareas.")
    else tareas.forEachIndexed { i, t -> println("$i: $t") }
}
"3" -> {
    print("Índice a eliminar: ")
    val idx = readLine()?.toIntOrNull()
    if (idx != null && idx in tareas.indices) {
        tareas.removeAt(idx)
        println("Tarea eliminada.")
    } else {
        println("Índice no válido.")
    }
}
```

> [!CUIDADO] Tres problemas de diseño
> - **Fuente y receptor mezclados**: cada rama es una reacción… pero vuelve a leer del teclado. Quien reacciona también decide cuándo pedir más datos.
> - **Estado, reacción y pantalla, todo junto**: la lista se modifica y se imprime desde el mismo sitio.
> - **Para añadir una opción hay que tocar el bucle**: cualquier cambio pasa por el corazón del programa.

**Preguntas**

**3.** ¿Qué llamada de agenda.kt bloquea el programa hasta que el usuario pulsa Intro?

**4.** ¿Qué problemas de diseño tiene agenda.kt?

   a) Las reacciones vuelven a leer del teclado: fuente y receptor mezclados
   b) No compila porque falta el `else` del `when`
   c) Para añadir una opción hay que modificar el bucle principal
   d) El estado se modifica y se muestra desde el mismo sitio

### Ejercicio: agenda.kt en ejecución · Ejercicio

Esto es lo que se ve en la consola de pde-consola tras dos vueltas del bucle:

```text
--- Agenda de tareas ---
1. Añadir tarea
2. Listar tareas
3. Eliminar tarea
4. Salir
Elige una opción: 1
Descripción de la tarea: Estudiar eventos
Tarea añadida.

--- Agenda de tareas ---
1. Añadir tarea
2. Listar tareas
3. Eliminar tarea
4. Salir
Elige una opción: 2
0: Estudiar eventos

--- Agenda de tareas ---
...
Elige una opción: ▌
```

Tres observaciones:

- **Lo que teclea el usuario** es la única información que entra en el programa, y solo se lee **cuando el programa lo pide**, nunca antes.
- **El menú se repinta en cada vuelta**: es el programa quien lleva la iniciativa.
- **El cursor parpadea: programa parado.** Está bloqueado en `readLine()`. No hace nada más hasta que pulses Intro: ni cuenta el tiempo, ni escucha la red, ni lee un sensor.

> [!EXAMEN] Pregunta para la clase
> Si mientras espera llegara un mensaje de red o venciera un temporizador, ¿se enteraría este programa? ¿Qué tendría que cambiar para que sí?

<details><summary>Ver respuesta</summary>
<p>No. Mientras está bloqueado en <code>readLine()</code> el programa solo puede recibir una línea de teclado: el teclado es su <b>única fuente</b> y está enterrada en el bucle. Para enterarse de otros sucesos haría falta separar las fuentes del bucle, que este no se quede bloqueado esperando solo al teclado y que cada suceso llegue como un <b>evento</b> a un receptor. Es justo el camino que empieza <code>agendaeventos.kt</code> y que Android ya resuelve con su propio bucle.</p>
</details>

**Preguntas**

**5.** Con el programa parado en `readLine()`, llega un mensaje de red. ¿Qué ocurre?

   a) El programa interrumpe la lectura y muestra el mensaje
   b) Nada: el programa no se entera, solo puede recibir lo que se teclea
   c) El `when` añade una rama nueva automáticamente
   d) El sistema operativo llama a la rama `else`

**6.** Partiendo de la agenda vacía, el usuario elige 1, escribe «Comprar pan», elige 1 otra vez, escribe «Llamar a Ana» y elige 2. ¿Qué línea se imprime para la segunda tarea?

### agendaeventos.kt (1/4): el evento y el estado · Teoría

Reescribimos el mismo programa separando **cuatro piezas**. El bucle deja de *decidir* y pasa a *entregar*:

<div class="flow">
  <div><b>Fuente</b><small>leerEvento(): lee el teclado y lo traduce. No ejecuta nada.</small></div>
  <div><b>Evento</b><small>EventoAgenda: qué ha pasado y con qué datos</small></div>
  <div><b>Receptor</b><small>manejar(): cambia el estado e imprime. No sabe cuándo le toca.</small></div>
  <div><b>Estado</b><small>EstadoAgenda: lo único que persiste entre eventos</small></div>
</div>

Y alrededor, el **bucle de eventos** en `main()`, que solo pide un evento y lo entrega.

Antes de leer nada del teclado, definimos **qué puede pasar**:

```kotlin
// --- Evento: qué puede pasar, con los datos que necesite cada caso ---
sealed class EventoAgenda {
    data class AnadirTarea(val descripcion: String) : EventoAgenda()
    object ListarTareas : EventoAgenda()
    data class EliminarTarea(val indice: Int) : EventoAgenda()
    object Salir : EventoAgenda()
    object OpcionInvalida : EventoAgenda()
}

// --- Estado: lo único que persiste entre eventos ---
class EstadoAgenda {
    val tareas = mutableListOf<String>()
    var enMarcha = true
}
```

- **Un tipo cerrado de sucesos**: con `sealed class` solo existen estos cinco eventos. El compilador obliga al receptor a tratarlos todos en el `when`.
- **El evento lleva sus datos**: `AnadirTarea` transporta la descripción; `EliminarTarea`, el índice. Ya no hay que volver a preguntar dentro de la reacción.
- **El estado, fuera del bucle**: lo que cambia entre evento y evento. En Android será `remember { mutableStateOf(...) }` o un campo de la Activity.

> [!NOTA] Compáralo con agenda.kt
> Allí «qué ha pasado» era un `String` (`"1"`, `"2"`…) comparado a mano. Aquí es un **valor con nombre y con datos**.

Fíjate en que `ListarTareas` o `Salir` son `object`: no necesitan datos, basta con una única instancia. `AnadirTarea` y `EliminarTarea` son `data class` porque cada evento lleva información distinta.

**Preguntas**

**7.** ¿Qué ventaja da declarar `EventoAgenda` como `sealed class`?

   a) Que los eventos se ejecutan más rápido
   b) Que solo existen los eventos declarados y el compilador obliga a tratarlos todos en el `when`
   c) Que no hace falta escribir un receptor
   d) Que los eventos se guardan automáticamente en disco

**8.** ¿Qué eventos de `EventoAgenda` transportan datos?

   a) `AnadirTarea`
   b) `ListarTareas`
   c) `EliminarTarea`
   d) `Salir`
   e) `OpcionInvalida`

### agendaeventos.kt (2/4 y 3/4): fuente y receptor · Teoría

## La fuente: `leerEvento()`

```kotlin
// --- Fuente: traduce entrada bruta de teclado en un evento con significado ---
fun leerEvento(): EventoAgenda {
    println("\n--- Agenda de tareas ---")
    println("1. Añadir tarea")
    println("2. Listar tareas")
    println("3. Eliminar tarea")
    println("4. Salir")
    print("Elige una opción: ")
    return when (readLine()?.trim()) {
        "1" -> {
            print("Descripción de la tarea: ")
            EventoAgenda.AnadirTarea(readLine() ?: "")
        }
        "2" -> EventoAgenda.ListarTareas
        "3" -> {
            print("Índice a eliminar: ")
            EventoAgenda.EliminarTarea(readLine()?.toIntOrNull() ?: -1)
        }
        "4" -> EventoAgenda.Salir
        else -> EventoAgenda.OpcionInvalida
    }
}
```

- **Sigue leyendo del teclado**, pero es el **único sitio** del programa donde ocurre: todo `readLine()` vive aquí.
- **Traduce, no ejecuta**: pide los datos que el evento necesita y lo construye. No añade, no borra, no lista.
- **Hasta el error es un evento**: una opción desconocida se devuelve como `OpcionInvalida` y ya decidirá el receptor.

## El receptor: `manejar()`

```kotlin
// --- Receptor: un manejador por tipo de evento ---
fun manejar(evento: EventoAgenda, estado: EstadoAgenda) {
    when (evento) {
        is EventoAgenda.AnadirTarea -> {
            estado.tareas.add(evento.descripcion)
            println("Tarea añadida.")
        }
        is EventoAgenda.ListarTareas -> {
            if (estado.tareas.isEmpty()) println("No hay tareas.")
            else estado.tareas.forEachIndexed { i, t -> println("$i: $t") }
        }
        is EventoAgenda.EliminarTarea -> {
            if (evento.indice in estado.tareas.indices) {
                estado.tareas.removeAt(evento.indice)
                println("Tarea eliminada.")
            } else {
                println("Índice no válido.")
            }
        }
        is EventoAgenda.Salir -> {
            estado.enMarcha = false
            println("Hasta luego.")
        }
        is EventoAgenda.OpcionInvalida -> println("Opción no reconocida.")
    }
}
```

- Un `when` sobre el **tipo** de evento: cinco eventos, cinco reacciones. Si olvidas uno, no compila.
- **Solo toca el estado** e imprime. **No lee del teclado**: los datos ya vienen dentro del evento (`evento.indice` ya está listo).
- **Salir también es una reacción**: no hay `break` ni `return` escondido; cambia `enMarcha` y el bucle terminará solo.

**Preguntas**

**9.** En agendaeventos.kt, ¿en qué función(es) aparece `readLine()`?

   a) En `leerEvento()` y en `manejar()`
   b) Solo en `main()`
   c) Solo en `leerEvento()`
   d) En las tres funciones

**10.** ¿Cómo consigue el evento `Salir` que termine el programa?

   a) Llamando a `exitProcess(0)` dentro de `manejar()`
   b) Con un `break` escondido en la fuente
   c) Cambiando `estado.enMarcha` a `false`, de modo que el bucle termina solo
   d) Lanzando una excepción que captura `main()`

### agendaeventos.kt (4/4): el bucle «tonto» · Teoría

```kotlin
// --- Bucle de eventos: ya no decide QUÉ hacer,
//     solo obtiene un evento y lo entrega ---
fun main() {
    val estado = EstadoAgenda()
    while (estado.enMarcha) {
        val evento = leerEvento()   // pide un evento
        manejar(evento, estado)     // lo entrega
    }
}
```

Cuatro líneas que **no saben nada de tareas**:

1. **Sigue habiendo un `while`.** Estamos en consola: nadie nos avisa, así que alguien tiene que preguntar. Pero el bucle ya no contiene ni un solo `"1"`, `"2"` o `"3"`.
2. **Pide un evento.** La fuente se encarga de esperar y traducir.
3. **Lo entrega.** El receptor se encarga de reaccionar. `main()` no sabe qué significa ninguno de los eventos.

Hemos pasado **de un bucle que decide a un bucle que entrega**. Añadir una opción nueva ya no toca esta parte.

![Arriba, agenda.kt: dentro de un único while (!salir), readLine() bloquea el programa, el when elige la rama entre «1» y «4» y las reacciones tocan estado y pantalla y vuelven a llamar a readLine(); después el bucle vuelve a preguntar. Abajo, agendaeventos.kt: el bucle while (estado.enMarcha) manejar(leerEvento(), estado) primero pide un evento a la fuente leerEvento(), que contiene el único readLine() y produce un EventoAgenda, y después lo entrega al receptor manejar(), que modifica EstadoAgenda (tareas, enMarcha). En naranja, los sitios donde se lee el teclado.](/img/pde/tema-1/agenda-vs-agendaeventos.svg "De un bucle que lo decide todo a un bucle que solo pide y entrega (en naranja, dónde se lee el teclado)")

## ¿Y en pde-plantilla, dónde está este `while`?

**No está en vuestro código.** Vive dentro de Android: es el **bucle de mensajes del hilo principal**. Vosotros solo escribís los receptores.

| Consola (agendaeventos.kt) | Android (pde-plantilla) |
| --- | --- |
| `while (estado.enMarcha) { ... }` escrito a mano | Bucle de mensajes del hilo principal, dentro de Android |
| `leerEvento()` | El sistema detecta toques y teclas y genera los eventos |
| `manejar(evento, estado)` | `setOnClickListener { ... }`: **vuestro manejar()** |
| `EstadoAgenda` | Campos de la Activity o `remember { mutableStateOf(...) }` |

> [!ANALOGIA]
> Lo que en consola habéis construido a mano, en Android **ya viene hecho**, y por eso parece que «nadie» decide el flujo. Sí hay alguien: el bucle del framework. Es la inversión de control de la lección anterior hecha código.

**Preguntas**

**11.** En una app Android, ¿dónde está el equivalente al `while` de `main()`?

   a) En el método `onCreate` que escribe el alumno
   b) Dentro de Android: el bucle de mensajes del hilo principal
   c) No existe: en Android no hay ningún bucle
   d) En cada `setOnClickListener`, que lleva su propio `while`

**12.** En Android, ¿qué llamada que usáis en pde-plantilla cumple el papel de vuestro `manejar()` para un botón?

### Ejercicio: ¿a qué pieza pertenece? · Ejercicio

Para cada trozo de código, decide a qué pieza de agendaeventos.kt pertenece: **fuente**, **evento**, **receptor**, **estado** o **bucle**.

| # | Fragmento |
| --- | --- |
| 1 | `EventoAgenda.EliminarTarea(readLine()?.toIntOrNull() ?: -1)` |
| 2 | `data class AnadirTarea(val descripcion: String) : EventoAgenda()` |
| 3 | `estado.tareas.removeAt(evento.indice)` |
| 4 | `var enMarcha = true` |
| 5 | `manejar(leerEvento(), estado)` dentro de `while (estado.enMarcha)` |
| 6 | `else -> EventoAgenda.OpcionInvalida` |

<details><summary>Ver solución</summary>
<p>1 → <b>fuente</b> (lee el teclado y construye el evento). 2 → <b>evento</b> (definición del tipo con sus datos). 3 → <b>receptor</b> (reacción que cambia el estado). 4 → <b>estado</b> (persiste entre eventos). 5 → <b>bucle</b> (pide y entrega). 6 → <b>fuente</b> (traduce una entrada desconocida en un evento; no la trata).</p>
</details>

> [!TRUCO] Cómo decidirlo rápido
> ¿Toca el teclado? Fuente. ¿Define *qué puede pasar*? Evento. ¿Cambia la lista o imprime el resultado? Receptor. ¿Sobrevive entre vuelta y vuelta? Estado. ¿Solo pide y entrega? Bucle.

**Preguntas**

**13.** ¿A qué pieza pertenece el fragmento 1, `EventoAgenda.EliminarTarea(readLine()?.toIntOrNull() ?: -1)`?

**14.** ¿Y el fragmento 3, `estado.tareas.removeAt(evento.indice)`?

   a) Fuente
   b) Evento
   c) Bucle
   d) Receptor

**15.** El fragmento 6, `else -> EventoAgenda.OpcionInvalida`, ¿en qué pieza está y por qué?

   a) En la fuente: traduce una entrada desconocida en un evento y deja que el receptor decida
   b) En el receptor: imprime «Opción no reconocida.»
   c) En el bucle: es la condición de salida
   d) En el estado: guarda el último error

### Ejercicio: añadir «Vaciar agenda» y predecir · Ejercicio

Queremos una opción nueva, **«5. Vaciar agenda»**, que borre todas las tareas.

**En agenda.kt** habría que meter una rama `"5" -> { ... }` en el `when` del bucle principal: el corazón del programa.

**En agendaeventos.kt** los cambios quedan repartidos así:

```kotlin
// Evento: un caso más
object VaciarAgenda : EventoAgenda()

// Fuente: una opción más en el menú y en la traducción
println("5. Vaciar agenda")
"5" -> EventoAgenda.VaciarAgenda

// Receptor: una reacción más
is EventoAgenda.VaciarAgenda -> {
    estado.tareas.clear()
    println("Agenda vaciada.")
}

// Bucle main(): ... ¡nada!
```

En un programa dirigido por eventos **basta con añadir un evento y su receptor** (y, en consola, enseñar a la fuente a producirlo). El bucle no se entera.

## Predice la salida

Con la agenda **vacía**, el usuario teclea `3` y, cuando le piden el índice, escribe `abc`.

Sigue el evento: `readLine()?.toIntOrNull()` devuelve `null` → el operador `?:` lo cambia por `-1` → la fuente devuelve `EliminarTarea(-1)` → el receptor comprueba si `-1` está en `estado.tareas.indices`…

**Preguntas**

**16.** Para añadir «Vaciar agenda» a agendaeventos.kt, ¿qué partes hay que modificar?

   a) La `sealed class EventoAgenda`
   b) La fuente `leerEvento()`
   c) El receptor `manejar()`
   d) El bucle de `main()`

**17.** ¿Qué imprime el receptor en el caso de `3` seguido de `abc`?

**18.** Ordena lo que ocurre en una vuelta del bucle cuando el usuario elige «2».

   Ordena: El receptor imprime la lista (o «No hay tareas.») · La fuente imprime el menú y se bloquea en `readLine()` · La fuente traduce «2» en `EventoAgenda.ListarTareas` · `main()` entrega el evento a `manejar()` · `main()` llama a `leerEvento()`

### Repaso: de un bucle que decide a un bucle que entrega · Repaso

> [!RESUMEN] Chuleta
> - **agenda.kt**: un `while` que lo decide todo. `readLine()` bloquea; es la única fuente y está dentro del bucle. Las reacciones vuelven a leer del teclado y mezclan estado y pantalla. Añadir una opción obliga a tocar el bucle.
> - **agendaeventos.kt** en cuatro piezas:
>   - **Evento**: `sealed class EventoAgenda` (tipo cerrado, cada caso con sus datos).
>   - **Fuente**: `leerEvento()`, único sitio con `readLine()`; traduce, no ejecuta; hasta el error es un evento.
>   - **Receptor**: `manejar()`, un `when` por tipo; solo toca el estado; sabe qué hacer, no cuándo.
>   - **Estado**: `EstadoAgenda` (`tareas`, `enMarcha`).
>   - **Bucle**: `while (estado.enMarcha) manejar(leerEvento(), estado)`.
> - **Android**: el bucle es el de mensajes del hilo principal; `setOnClickListener { … }` es vuestro `manejar()`.

| | agenda.kt | agendaeventos.kt |
| --- | --- | --- |
| «Qué ha pasado» | Un `String` comparado a mano | Un valor con nombre y datos |
| Dónde se lee el teclado | En el bucle y en las reacciones | Solo en la fuente |
| Añadir una opción | Tocar el bucle | Evento + traducción + reacción |
| Quién decide qué hacer | El bucle | El receptor |

**Preguntas**

**19.** En agendaeventos.kt, ¿quién decide **qué** hacer con cada suceso?

   a) El bucle de `main()`
   b) La fuente `leerEvento()`
   c) El receptor `manejar()`
   d) La clase `EstadoAgenda`

**20.** ¿Qué equivale en Android a `EstadoAgenda`?

   a) El bucle de mensajes del hilo principal
   b) Un campo de la Activity o `remember { mutableStateOf(...) }`
   c) El método `setOnClickListener`
   d) El fichero `AndroidManifest.xml`

**21.** ¿Por qué agendaeventos.kt sigue necesitando un `while`?

   a) Porque Kotlin no permite programas sin bucles
   b) Porque en consola nadie nos avisa: alguien tiene que preguntar por el siguiente suceso
   c) Porque la `sealed class` lo exige
   d) Por error: debería eliminarse

### Solucionario

1. b) Qué hacer, pero no cuándo le toca  
   El receptor contiene la reacción (**qué** hacer); **cuándo** se ejecuta lo decide quien le entrega el evento.
2. c) El teclado y la función que lo lee  
   En consola, los sucesos llegan del **teclado**, y la función que lo lee (con `readLine()`) es la que los origina en el programa.
3. `readLine()`  
   `readLine()` detiene el programa hasta recibir una línea. Es la única fuente de sucesos y está metida dentro del bucle.
4. a) Las reacciones vuelven a leer del teclado: fuente y receptor mezclados; c) Para añadir una opción hay que modificar el bucle principal; d) El estado se modifica y se muestra desde el mismo sitio  
   El `when` sí tiene `else`. Los problemas son de diseño: fuente y receptor mezclados, estado/reacción/pantalla juntos y un bucle que hay que tocar ante cualquier cambio.
5. b) Nada: el programa no se entera, solo puede recibir lo que se teclea  
   El teclado es la única fuente y el programa está bloqueado esperándola. Ni temporizadores ni red ni sensores pueden llegar a él.
6. `1: Llamar a Ana`  
   `forEachIndexed` numera desde 0: se imprime «0: Comprar pan» y **«1: Llamar a Ana»**.
7. b) Que solo existen los eventos declarados y el compilador obliga a tratarlos todos en el `when`  
   Un tipo cerrado: no puede aparecer un sexto evento por sorpresa y, si el receptor olvida uno, no compila.
8. a) `AnadirTarea`; c) `EliminarTarea`  
   `AnadirTarea` lleva la descripción y `EliminarTarea` el índice. Los demás son `object` sin datos.
9. c) Solo en `leerEvento()`  
   La fuente es el único sitio que toca el teclado. El receptor recibe los datos ya empaquetados dentro del evento.
10. c) Cambiando `estado.enMarcha` a `false`, de modo que el bucle termina solo  
   Salir es una reacción más: modifica el estado (`enMarcha = false`) y la condición del `while` hace el resto.
11. b) Dentro de Android: el bucle de mensajes del hilo principal  
   El bucle sigue existiendo, pero lo escribe el framework: es el bucle de mensajes del hilo principal. Vosotros solo aportáis los receptores.
12. `setOnClickListener`  
   `setOnClickListener { … }` registra el receptor del clic: es vuestro `manejar()`.
13. `fuente`  
   Lee del teclado y **construye** el evento con su dato: es trabajo de la **fuente**.
14. d) Receptor  
   Usa el dato que trae el evento para cambiar el estado: es una **reacción**, parte del receptor `manejar()`.
15. a) En la fuente: traduce una entrada desconocida en un evento y deja que el receptor decida  
   Hasta el error es un evento. La fuente no lo trata: lo devuelve como `OpcionInvalida` y el receptor imprime el mensaje.
16. a) La `sealed class EventoAgenda`; b) La fuente `leerEvento()`; c) El receptor `manejar()`  
   Evento nuevo, traducción nueva en la fuente y reacción nueva en el receptor. `main()` no cambia: solo pide y entrega.
17. `Índice no válido.`  
   `-1` no está en los índices de la lista, así que el receptor imprime **«Índice no válido.»**
18. 1. `main()` llama a `leerEvento()` → 2. La fuente imprime el menú y se bloquea en `readLine()` → 3. La fuente traduce «2» en `EventoAgenda.ListarTareas` → 4. `main()` entrega el evento a `manejar()` → 5. El receptor imprime la lista (o «No hay tareas.»)  
   El bucle pide → la fuente espera y traduce → el bucle entrega → el receptor reacciona.
19. c) El receptor `manejar()`  
   El bucle solo pide y entrega; la fuente solo traduce. La decisión de qué hacer vive en el receptor.
20. b) Un campo de la Activity o `remember { mutableStateOf(...) }`  
   El estado es lo que persiste entre eventos: en Android, un campo de la Activity o un estado de Compose con `remember { mutableStateOf(...) }`.
21. b) Porque en consola nadie nos avisa: alguien tiene que preguntar por el siguiente suceso  
   En consola no hay framework que entregue eventos, así que el bucle lo escribimos nosotros. En Android lo escribe el sistema.

## Debate: ¿fuente, evento o receptor?

_Diez situaciones de la vida real (clics, timeouts, mensajes, sensores y cambios de datos) para practicar la clasificación fuente / evento / receptor y descubrir quién escribe el bucle._

### Las reglas del debate · Ejercicio

Diez situaciones cotidianas, agrupadas en cinco familias: **clic**, **timeout**, **mensaje recibido**, **sensor** y **cambio de datos**. Para cada una hay que rellenar tres columnas:

| Fuente | Evento | Receptor |
| --- | --- | --- |
| ¿Quién origina el suceso? | ¿Qué ocurre exactamente, y con qué datos? | ¿Qué código está escuchando y reacciona? |

> [!IMPORTANTE] Regla del debate
> **Las tres columnas tienen que ser cosas distintas.** Si fuente y evento os salen iguales, revisadlo. Y una pregunta extra: **¿quién escribió el receptor: vosotros, el framework o el sistema operativo?**

Intenta resolver cada tarjeta **antes** de girarla:

> _Aquí hay un simulador interactivo (`fer-cards`): ábrelo en la web._
En los pasos siguientes repasaremos las diez situaciones con las respuestas del profesor, de dos en dos o de cuatro en cuatro, y nos fijaremos en las trampas típicas: confundir la fuente con el canal, o el evento con el dispositivo que lo produce.

**Preguntas**

**1.** Un grupo propone para «el usuario pulsa Enviar»: fuente = «el botón Enviar», evento = «el botón Enviar», receptor = «el formulario». ¿Qué falla?

   a) Nada, es correcto
   b) Fuente y evento son iguales: el evento debe ser lo que ocurre (el clic) con sus datos
   c) El receptor debería ser el usuario
   d) Falta indicar el sistema operativo como evento

**2.** ¿Cuáles de estas son familias de situaciones del debate?

   a) Clic
   b) Compilación
   c) Timeout
   d) Sensor
   e) Cambio de datos
   f) Herencia

### Situaciones 1-4: clics y timeouts · Ejercicio

| # | Situación | Fuente | Evento | Receptor |
| --- | --- | --- | --- | --- |
| 01 | El usuario pulsa «Enviar» en un formulario web. | El usuario, a través del ratón o la pantalla táctil, y el navegador que capta el clic. | Clic en el botón «Enviar», con el elemento pulsado y los datos del formulario. | El manejador `onSubmit` / `addEventListener('click', …)` que valida y envía la petición. |
| 02 | Doble clic sobre un icono del escritorio. | El usuario + el controlador del ratón / sistema operativo, que detecta el patrón de doble clic. | «Doble clic sobre el icono X». | El manejador del escritorio que abre la aplicación asociada. |
| 03 | Una petición HTTP no recibe respuesta en 5 segundos. | El temporizador (timer) del cliente HTTP. | Vencimiento del plazo de espera a los 5000 ms. | El callback `onTimeout` / bloque `catch` que cancela la petición y muestra un error. |
| 04 | Una sesión se cierra sola tras 15 minutos de inactividad. | El temporizador de inactividad del servidor o de la aplicación. | Expiración de la sesión. | El manejador que invalida la sesión y redirige al login. |

**Qué aprender de estas cuatro:**

- En los **clics** la fuente no es solo "el usuario": hay una pieza que **capta** el suceso (navegador, controlador del ratón, SO). En el doble clic, además, alguien tiene que **reconocer el patrón** de dos clics seguidos.
- En los **timeouts** no hay ninguna persona: la fuente es un **temporizador**. El evento es justamente que *no* ha pasado nada durante un plazo.

> [!NOTA] ¿Quién escribió el receptor?
> En la 01, el manejador del formulario lo escribe quien desarrolla la web. En la 02, el manejador que abre la aplicación forma parte del **escritorio del sistema operativo**: nadie de vosotros lo ha escrito.

**Preguntas**

**3.** En la situación 3 (petición HTTP sin respuesta en 5 s), ¿quién es la fuente?

   a) El servidor que no responde
   b) El usuario que hizo la petición
   c) El temporizador del cliente HTTP
   d) El bloque `catch`

**4.** En la situación 1, ¿cuál es el receptor?

   a) El navegador que capta el clic
   b) El manejador `onSubmit` / `addEventListener('click', …)` que valida y envía
   c) Los datos del formulario
   d) El ratón

**5.** En la situación 4, completa el evento: «______ de la sesión».

### Situaciones 5-6: mensajes recibidos · Ejercicio

| # | Situación | Fuente | Evento | Receptor |
| --- | --- | --- | --- | --- |
| 05 | Llega un mensaje nuevo de WhatsApp al móvil. | El servidor de mensajería, que empuja la notificación al dispositivo. | «Mensaje entrante», con remitente y contenido. | El servicio de notificaciones de la app, que muestra el aviso. |
| 06 | Un microservicio recibe en una cola (Kafka / RabbitMQ) el aviso de que un pedido se ha pagado. | El servicio de pagos, que publica el mensaje en la cola. | Mensaje «PedidoPagado» con el identificador del pedido. | El consumidor (listener) suscrito a la cola, que actualiza el estado del pedido. |

**Qué aprender de estas dos:**

- En la **05**, desde el punto de vista del móvil, la fuente inmediata es el **servidor de mensajería** que empuja la notificación. Tu amigo escribió el mensaje, pero el suceso que llega al dispositivo lo origina el servidor.
- En la **06** aparece una trampa clásica: **la cola no es la fuente**. Kafka o RabbitMQ son el **canal** por el que viaja la notificación. Quien origina el suceso es el **servicio de pagos**, que *publica*; quien reacciona es el **consumidor suscrito**.

<div class="flow">
  <div><b>Servicio de pagos</b><small>fuente: publica</small></div>
  <div><b>Cola Kafka / RabbitMQ</b><small>canal: transporta</small></div>
  <div><b>Consumidor</b><small>receptor: actualiza el pedido</small></div>
</div>

> [!EXAMEN]
> Distingue siempre **quién origina** el suceso de **por dónde viaja**. Este patrón de publicar / suscribirse lo veréis con detalle en la Unidad 2 (pub/sub).

**Preguntas**

**6.** En la situación 6 (Kafka / RabbitMQ), ¿quién es la fuente?

   a) La cola de Kafka / RabbitMQ
   b) El consumidor suscrito a la cola
   c) El servicio de pagos, que publica el mensaje
   d) El mensaje «PedidoPagado»

**7.** ¿Qué dato lleva el evento «PedidoPagado», según la respuesta del profesor?

**8.** En la situación 5 (WhatsApp), ¿qué datos acompañan al evento «Mensaje entrante»?

   a) Remitente
   b) Contenido
   c) Nivel de batería del móvil
   d) Orientación de la pantalla

### Situaciones 7-8: sensores · Ejercicio

| # | Situación | Fuente | Evento | Receptor |
| --- | --- | --- | --- | --- |
| 07 | El acelerómetro del móvil detecta que has girado la pantalla. | El sensor de orientación (hardware) y su controlador. | Cambio de orientación: de vertical a horizontal. | El `OrientationEventListener` / el sistema de diseño que recoloca la interfaz. |
| 08 | El sensor de temperatura de una nevera inteligente detecta que sube por encima del umbral. | El sensor de temperatura del electrodoméstico. | «Temperatura > umbral», con el valor leído. | El manejador que dispara una alerta al móvil del usuario. |

**Qué aprender de estas dos:**

- Aquí la fuente es **hardware**. Conecta con la lección 1: estímulo físico → detección (polling o interrupción) → driver/controlador → evento software → reacción. En la 07 la respuesta menciona explícitamente "el sensor **y su controlador**".
- El evento no es "el sensor", sino **lo que ha cambiado** y con qué datos: la nueva orientación, o el valor de temperatura que ha superado el umbral.
- En la 08 el evento no es cada lectura, sino un suceso **con significado**: cruzar el umbral. Alguien ha convertido muchas medidas en un único evento relevante.

> [!NOTA] ¿Quién escribió el receptor?
> En la 07 hay dos posibilidades, y la respuesta del profesor recoge ambas: si registras un `OrientationEventListener`, el receptor lo escribes **tú**; si dejas que el sistema recoloque la interfaz, el receptor es del **framework**.

**Preguntas**

**9.** En la situación 7, ¿cuál es el **evento**?

   a) El acelerómetro
   b) El cambio de orientación de vertical a horizontal
   c) El `OrientationEventListener`
   d) La interfaz recolocada

**10.** Ordena la cadena de la situación 8, de la fuente a la reacción.

   Ordena: El manejador recibe el evento · El sensor de temperatura de la nevera mide · Se dispara una alerta al móvil del usuario · Se produce el evento «Temperatura > umbral» con el valor leído

### Situaciones 9-10: cambios de datos · Ejercicio

| # | Situación | Fuente | Evento | Receptor |
| --- | --- | --- | --- | --- |
| 09 | Alguien edita una celda de una hoja de cálculo colaborativa y los demás lo ven al momento. | El usuario que edita + el servidor de sincronización que propaga el cambio. | «Celda A1 modificada», con el nuevo valor. | El listener de cada cliente conectado, que repinta esa celda. |
| 10 | Añades un producto al carrito y el icono del carrito cambia de número. | El propio código de la app: el clic en «Añadir al carrito» modificó una variable de estado. | Cambio del estado *carrito* (nueva lista / tamaño). | La parte de la interfaz que observa ese estado (icono con contador) y se recompone o se repinta. |

**Qué aprender de estas dos:**

- En la **09** un único evento tiene **muchos receptores**: el listener de *cada* cliente conectado. La fuente es doble: quien edita y el servidor que propaga.
- La **10** es la más sutil: la fuente es **tu propio código**. El clic provocó un cambio de estado, y ese **cambio de estado es a su vez un evento** que escucha otra parte de la interfaz. Un evento produce otro.

> [!IMPORTANTE] El estado como fuente de eventos
> Esta idea (una parte de la interfaz que **observa** un estado y se repinta sola cuando cambia) es la base del patrón Observer y de MVVM, que llegarán en la Unidad 2. En pde-plantilla, de momento, la llamáis a mano con `actualizarInterfaz()`.

**Preguntas**

**11.** En la situación 10 (carrito), ¿cuál es la fuente según la respuesta del profesor?

   a) El servidor de la tienda
   b) El propio código de la app, que modificó una variable de estado tras el clic
   c) El icono del carrito
   d) El sistema operativo del móvil

**12.** En la situación 9, ¿cuántos receptores tiene el evento «Celda A1 modificada»?

   a) Ninguno: el servidor repinta todas las pantallas
   b) Solo uno: el usuario que editó
   c) Uno por cada cliente conectado: el listener de cada uno repinta la celda
   d) Exactamente dos: el servidor y el editor

### ¿Quién escribe el bucle? · Teoría

Tras pasar por pde-plantilla, pde-consola y la vida real, aparece siempre lo mismo:

<div class="cards">
  <div class="card"><h4>pde-plantilla</h4><p>El bucle existe, pero <b>vive dentro de Android</b>. Vosotros escribís los receptores (los listeners)… y <code>actualizarInterfaz()</code> a mano.</p></div>
  <div class="card"><h4>pde-consola</h4><p>El bucle lo habéis <b>escrito vosotros</b> con un <code>while</code>. Primero decidía todo; después solo pide un evento y lo entrega.</p></div>
  <div class="card"><h4>Vida real</h4><p><b>No hay bucle de código</b>: el mundo (personas, sensores, redes, temporizadores) genera eventos sin parar. Alguien tiene que escuchar.</p></div>
</div>

<div class="flow">
  <div><b>Fuente</b><small>quién origina</small></div>
  <div><b>Evento</b><small>qué pasa + datos</small></div>
  <div><b>Receptor</b><small>quién reacciona</small></div>
</div>

**Misma estructura en los tres: fuente → evento → receptor.** Solo cambia **dónde vive el bucle** que busca el siguiente suceso y **quién repinta la pantalla**.

![Tres columnas con la misma cadena fuente, evento y receptor. pde-plantilla (Android): usuario y pantalla, clic en el botón, setOnClickListener; el bucle está dentro de Android, es el bucle de mensajes. pde-consola (agendaeventos.kt): leerEvento(), EventoAgenda, manejar(); el bucle lo escribís vosotros con un while que pide y entrega. Vida real (nevera inteligente): sensor de temperatura, temperatura por encima del umbral, manejador de alerta; no hay bucle de código, el mundo genera los eventos. Debajo: el bucle siempre existe; la pregunta es quién lo escribe.](/img/pde/tema-1/quien-escribe-el-bucle.svg "Misma cadena en los tres contextos; solo cambia quién escribe el bucle")

## ¿Quién escribió el receptor?

Repasa las situaciones con esta pregunta:

| Quién lo escribe | Ejemplos del debate |
| --- | --- |
| **Vosotros** (la aplicación) | El `onSubmit` del formulario (01), el consumidor de «PedidoPagado» (06), el manejador que alerta de la nevera (08) |
| **El framework** | El sistema de diseño que recoloca la interfaz al girar (07, si no registras listener propio) |
| **El sistema operativo** | El manejador del escritorio que abre la aplicación (02) |

> [!RESUMEN] Para cerrar
> **El bucle siempre existe. La pregunta es quién lo escribe.**

**Preguntas**

**13.** ¿En qué contexto **habéis escrito vosotros** el bucle de eventos?

   a) pde-plantilla (Android)
   b) pde-consola (agendaeventos.kt)
   c) La vida real
   d) En ninguno

**14.** Completa la frase de cierre: «El bucle siempre existe. La pregunta es quién lo ______.»

### Repaso del debate · Repaso

> [!RESUMEN] Chuleta del debate
> - **Fuente**: quién origina (persona + dispositivo que capta, temporizador, servidor que publica, sensor, o el propio código al cambiar estado).
> - **Evento**: qué ocurre exactamente **y con qué datos** (elemento pulsado, 5000 ms, remitente y contenido, id del pedido, valor leído, nuevo valor de la celda).
> - **Receptor**: el código que escucha y reacciona (manejador, callback, listener, consumidor, interfaz que observa).
> - Las tres columnas **deben ser distintas**.
> - Un **canal** (cola, red) no es la fuente: solo transporta.
> - Un evento puede tener **muchos receptores** (hoja colaborativa) y un evento puede **provocar otro** (carrito).
> - Misma estructura siempre; cambia **dónde vive el bucle** y **quién escribe el receptor**.

| Familia | Fuente típica |
| --- | --- |
| Clic | Usuario + dispositivo / navegador / SO |
| Timeout | Temporizador |
| Mensaje recibido | Servidor o servicio que publica |
| Sensor | Hardware + controlador |
| Cambio de datos | Quien edita / el propio estado de la app |

**Preguntas**

**15.** En una situación de tipo **timeout**, ¿qué suele ser la fuente?

   a) El usuario
   b) Un temporizador
   c) El receptor
   d) La cola de mensajes

**16.** Nueva situación: «La alarma del móvil suena a las 7:00 y la app muestra el botón de posponer». ¿Qué clasificación respeta la regla del debate?

   a) Fuente: la alarma · Evento: la alarma · Receptor: el móvil
   b) Fuente: el temporizador del sistema · Evento: «hora programada alcanzada (7:00)» · Receptor: el manejador de la app que muestra la pantalla de alarma
   c) Fuente: el usuario · Evento: el botón posponer · Receptor: el temporizador
   d) Fuente: la pantalla · Evento: las 7:00 · Receptor: el usuario

**17.** ¿Qué papel juega la cola Kafka en la situación 6?

   a) Es la fuente del evento
   b) Es el receptor que actualiza el pedido
   c) Es el canal por el que viaja la notificación entre fuente y receptor
   d) Es el propio evento

### Solucionario

1. b) Fuente y evento son iguales: el evento debe ser lo que ocurre (el clic) con sus datos  
   Si dos columnas coinciden, algo falla. El evento es **el clic en Enviar**, con el elemento pulsado y los datos del formulario.
2. a) Clic; c) Timeout; d) Sensor; e) Cambio de datos  
   Las cinco familias son clic, timeout, mensaje recibido, sensor y cambio de datos.
3. c) El temporizador del cliente HTTP  
   La fuente es el **timer del cliente HTTP**: es quien origina el suceso «ha vencido el plazo». El `catch` / `onTimeout` es el receptor.
4. b) El manejador `onSubmit` / `addEventListener('click', …)` que valida y envía  
   El receptor es el código que escucha y reacciona: el manejador que valida y envía la petición.
5. `expiración`  
   El evento es la **expiración de la sesión**; la fuente, el temporizador de inactividad; el receptor, el manejador que la invalida y redirige al login.
6. c) El servicio de pagos, que publica el mensaje  
   La fuente es el **servicio de pagos**. La cola es el canal, «PedidoPagado» es el evento y el consumidor es el receptor.
7. `el identificador del pedido`  
   El mensaje «PedidoPagado» lleva el **identificador del pedido**, para que el consumidor sepa qué pedido actualizar.
8. a) Remitente; b) Contenido  
   El evento «mensaje entrante» lleva **remitente y contenido**.
9. b) El cambio de orientación de vertical a horizontal  
   El acelerómetro (y su controlador) es la fuente; el `OrientationEventListener` o el sistema de diseño, el receptor; la interfaz recolocada, la reacción. El evento es el **cambio de orientación**.
10. 1. El sensor de temperatura de la nevera mide → 2. Se produce el evento «Temperatura > umbral» con el valor leído → 3. El manejador recibe el evento → 4. Se dispara una alerta al móvil del usuario  
   Fuente (sensor) → evento con su dato → receptor (manejador) → reacción (alerta al móvil).
11. b) El propio código de la app, que modificó una variable de estado tras el clic  
   La fuente es el propio código: el clic modificó el estado *carrito* y ese cambio es el evento que observa el icono con el contador.
12. c) Uno por cada cliente conectado: el listener de cada uno repinta la celda  
   Cada cliente conectado tiene su listener, que repinta la celda. Un evento, muchos receptores.
13. b) pde-consola (agendaeventos.kt)  
   En consola el `while` es vuestro. En Android vive dentro del framework y en la vida real no hay bucle de código: el mundo genera eventos.
14. `escribe`  
   **El bucle siempre existe. La pregunta es quién lo escribe**: vosotros (consola), el framework (Android) o nadie en código (el mundo real, donde alguien tiene que escuchar).
15. b) Un temporizador  
   En las situaciones 3 y 4 la fuente es un temporizador (del cliente HTTP o de inactividad).
16. b) Fuente: el temporizador del sistema · Evento: «hora programada alcanzada (7:00)» · Receptor: el manejador de la app que muestra la pantalla de alarma  
   Es un caso de timeout: la fuente es un temporizador, el evento es el vencimiento con su dato (la hora) y el receptor es el código que reacciona.
17. c) Es el canal por el que viaja la notificación entre fuente y receptor  
   La cola transporta el mensaje. Fuente: servicio de pagos; evento: «PedidoPagado»; receptor: el consumidor suscrito.
