This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
8. Loading data
What you’ll learn: fetching data without freezing the UI and displaying large lists efficiently. Prerequisites: Managing state.
Complete example (copy, paste, and run)
Loads the data on a background Thread, comes back to the paint thread with Component.onUI, and displays it in a
virtualized list (VirtualListView + DataAdapter) that recycles views. Compiles as is.
package com.exemplo;
import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
public class MainWindow extends Window
{
private final List<Tarefa> tarefas = new ArrayList<>();
private VirtualListView lista;
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter()
{
public int getCount() { return tarefas.size(); }
public Component createView() { return new Label(""); } // creates once
public void bindView(Component v, int i) { ((Label) v).setText(tarefas.get(i).titulo); }
});
add(LAY_FILL, lista);
carregar();
}
private void carregar()
{
new Thread(() -> {
var dados = listarDoRepositorio(); // heavy work, background thread
Component.onUI(() -> { // back to the paint thread
tarefas.clear();
tarefas.addAll(dados);
lista.notifyDataChanged(); // updates the virtualized list
});
}).start();
}
private List<Tarefa> listarDoRepositorio() // simulates I/O
{
List<Tarefa> out = new ArrayList<>();
for (int i = 1; i <= 500; i++) out.add(new Tarefa("Tarefa " + i));
return out;
}
}
class Tarefa
{
final String titulo;
Tarefa(String titulo) { this.titulo = titulo; }
}
The snippets below show only the core (what goes inside
onShow()). To run them, put them in theMainWindowskeleton above.
Why I/O never happens on the paint thread
The UI runs on a single thread — any blocking on it freezes the screen. The mandatory pattern:
new Thread(() -> {
var dados = repo.listar(); // heavy work, background thread
Component.onUI(() -> { // back to the paint thread
vm.tarefas = dados;
lista.notifyDataChanged(); // updates the virtualized list
});
}).start();
To react to a UI event already in the background, use onActionThread (see
Handling input).
Large lists: VirtualListView + DataAdapter
VirtualListView recycles views — it renders only what’s visible. The adapter separates creating (once) from
binding (cheap, many times):
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter() {
public int getCount() { return vm.tarefas.size(); }
public Component createView() throws Exception { return new CardTarefa(); }
public void bindView(Component v, int i) throws Exception { ((CardTarefa) v).bind(vm.tarefas.get(i)); }
});
add(LAY_FILL, lista);
// when the data changes:
lista.notifyDataChanged();
bindViewruns a lot during scroll — keep it cheap and idempotent (no I/O in there).
What you build in this step
The list now loads in the background and renders virtualized (using the CardTarefa from
chapter 3).
Recap
I/O in a Thread → Component.onUI; large lists with VirtualListView (recycling via
createView/bindView); notifyDataChanged() when the data changes.