Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.
7. Gestionando el estado
Lo que vas a aprender: el modelo de estado de CrossFly — donde quien viene de Flutter/React necesita desaprender. Prerrequisitos: Manejando la entrada.
Ejemplo completo (copiar, pegar y ejecutar)
Una ViewModel liviana (TarefaVM) con observe(Runnable) manual (no hay binding reactivo): la View re-puebla
los componentes cuando el estado cambia. Un botón agrega tareas y la lista se re-renderiza. Compila tal cual.
package com.exemplo;
import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
public class MainWindow extends Window
{
private final TarefaVM vm = new TarefaVM();
private final Component listaBox = new Component();
private int contador = 1;
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
Button add = new Button("Adicionar tarefa");
add.onAction(c -> vm.adicionar(new Tarefa("Tarefa " + (contador++))));
add(LAY_AUTO, add);
listaBox.setLayout(new VerticalLayout());
add(LAY_FILL, listaBox);
vm.observe(this::renderizarLista); // re-puebla cuando el estado cambia
renderizarLista();
}
private void renderizarLista()
{
listaBox.removeAll();
for (Tarefa t : vm.tarefas) listaBox.add(LAY_AUTO, new Label(t.titulo));
listaBox.setValidLayout(false); // el tamaño cambió
Component.repaint();
}
}
class Tarefa
{
final String titulo;
Tarefa(String titulo) { this.titulo = titulo; }
}
class TarefaVM
{
private Runnable onChange;
public List<Tarefa> tarefas = new ArrayList<>();
public void observe(Runnable r) { this.onChange = r; }
private void mudou() { if (onChange != null) onChange.run(); }
public void adicionar(Tarefa t)
{
var novo = new ArrayList<>(tarefas); novo.add(t);
tarefas = novo;
mudou(); // notifica a la View (en el paint thread)
}
}
Los fragmentos de abajo muestran solo el núcleo (lo que va dentro de
onShow()). Para ejecutar, colócalos en el esqueletoMainWindowde arriba.
No hay binding reactivo
Cambiar el modelo no actualiza la UI solo. El estado vive en campos (o en una ViewModel liviana), y la
View traduce estado → componentes manualmente, llamando a repaint() (y setValidLayout(false) si el
tamaño cambió).
Una ViewModel liviana con observe
public class TarefaVM {
private Runnable onChange;
public List<Tarefa> tarefas = List.of();
public void observe(Runnable r) { this.onChange = r; }
private void mudou() { if (onChange != null) onChange.run(); }
public void adicionar(Tarefa t) {
var novo = new ArrayList<>(tarefas); novo.add(t);
tarefas = novo;
mudou(); // notifica a la View (en el paint thread)
}
}
La View reacciona
@Override public void onShow() throws Exception {
super.onShow();
// … monta UI …
vm.observe(this::renderizarLista); // re-puebla los componentes cuando el estado cambia
vm.carregar(); // dispara la carga (en background — próximo capítulo)
}
private void renderizarLista() {
listaBox.removeAll();
for (Tarefa t : vm.tarefas) { CardTarefa card = new CardTarefa(); listaBox.add(LAY_AUTO, card); card.bind(t); }
listaBox.setValidLayout(false);
Component.repaint();
}
Regla: las mutaciones y notificaciones siempre en la paint thread. Si el dato vino de fondo, entra en
Component.onUI(...)antes de tocar el estado que la View lee (ver próximo capítulo).
Construyes en este paso
La TarefaVM con la pantalla re-renderizándose cuando el estado cambia.
Recapitulando
Sin reactivo: estado en campos/ViewModel; la View traduce estado→componentes con repaint(); un
observe(Runnable) manual sustituye el binding.
Próximos pasos
Ver también
- Concepto: Estado y flujo de datos · Arquitectura de app